/* global React */
// ============================================================
// Pointage / temps de travail des VA (shift clock)
// ------------------------------------------------------------
// 4 états : 🟢 travaille (panel ouvert + action < 5 min) · 😴 inactif (panel ouvert,
// rien > 5 min, hors pause) · ☕/🚽/🍽️ pause (déclarée) · ⚫ hors panel.
// Le temps s'accumule PAR JOUR et PAR VA. Persisté dans le store partagé D1 « shifts »,
// fusionné par (jour, userId) « le plus récent gagne » (plusieurs VA écrivent en parallèle).
// L'accumulation tourne côté navigateur du VA (source de vérité de SON shift) ; l'owner lit.
// ============================================================
(function () {
  const IDLE_MS = 5 * 60 * 1000;   // 5 min sans action -> inactif
  const TICK_MS = 1000;            // granularité d'accumulation (1 s -> affichage vivant)
  const SAVE_MS = 20000;           // flush backend
  const SHIFT_KEY = "phonelabs.shifts";

  function dayKey(ts) { const d = new Date(ts); return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0"); }
  function uid() { return (window.__FARM_USER__ && (window.__FARM_USER__.id || window.__FARM_USER__.name)) || ""; }
  function uname() { return (window.__FARM_USER__ && window.__FARM_USER__.name) || ""; }

  const load = () => { try { return JSON.parse(localStorage.getItem(SHIFT_KEY)) || {}; } catch (e) { return {}; } };
  const saveLocal = (m) => { try { localStorage.setItem(SHIFT_KEY, JSON.stringify(m)); } catch (e) {} };
  const subs = new Set();
  const emit = () => subs.forEach(f => { try { f(); } catch (e) {} });

  // fusion { jour: { uid: rec } } — pour chaque (jour,uid) on garde la rec au updatedAt le plus grand
  function mergeMaps(a, b) {
    const out = {}; const days = new Set([...Object.keys(a || {}), ...Object.keys(b || {})]);
    days.forEach(day => {
      out[day] = {}; const ua = (a && a[day]) || {}, ub = (b && b[day]) || {};
      new Set([...Object.keys(ua), ...Object.keys(ub)]).forEach(u => {
        const ra = ua[u], rb = ub[u];
        out[day][u] = (!rb || (ra && (ra.updatedAt || 0) >= (rb.updatedAt || 0))) ? ra : rb;
      });
    });
    return out;
  }
  async function syncBackend() {
    if (!(window.Backend && window.Backend.getStore && window.__FARM_USER__)) return;
    let r = null; try { r = await window.Backend.getStore("shifts"); } catch (e) {}
    if (!r) return;                                   // backend injoignable -> lecture seule, aucune perte
    const remote = (r.value && r.value.data) || {};
    const merged = mergeMaps(load(), remote);
    saveLocal(merged); emit();
    try { if (window.Backend.saveStore) window.Backend.saveStore("shifts", { savedAt: new Date().toISOString(), data: merged }); } catch (e) {}
  }

  // ---- état live du shift (en mémoire) ----
  // `ended` : le VA a explicitement Terminé -> stoppe le pointage MÊME panel ouvert.
  // Modèle INCRÉMENTAL : chaque seconde on ajoute le temps écoulé au bon compteur (persisté).
  // Le compteur ne fait que MONTER (jamais de reset). Onglet caché / hors shift -> pas compté.
  const S = { panels: 0, shiftOn: false, ended: false, breakType: null, breakStart: 0, lastAct: Date.now(),
              lastTick: Date.now(), sessionStart: 0, sessionBase: null, idleNotified: false };

  function onShift() { return !S.ended && (S.shiftOn || S.panels > 0); }
  function effState() {
    if (!onShift()) return "off";
    if (S.breakType) return "break";
    if (Date.now() - S.lastAct > IDLE_MS) return "idle";
    return "work";
  }
  function todayRec() {
    const m = load(); const dk = dayKey(Date.now()); const u = uid();
    m[dk] = m[dk] || {};
    m[dk][u] = m[dk][u] || { name: uname(), worked: 0, idle: 0, brk: 0, cafe: 0, wc: 0, lunch: 0, updatedAt: Date.now() };
    return { m, dk, u, rec: m[dk][u] };
  }
  const _hidden = () => (typeof document !== "undefined" && document.hidden);
  function beginSession() { if (S.sessionStart) return; S.sessionStart = Date.now(); const { rec } = todayRec(); S.sessionBase = { worked: rec.worked, idle: rec.idle, brk: rec.brk }; }

  // comptabilise le temps écoulé depuis le dernier tick dans le bon compteur (borné pour ignorer les gros trous)
  function accumulate() {
    const now = Date.now(); let dt = (now - S.lastTick) / 1000; S.lastTick = now;
    if (dt > 300) dt = 300;                                         // gros écart (veille système / absence longue) -> plafonné à 5 min
    // NB : on compte le temps MÊME onglet caché (le VA bosse souvent sur un autre onglet/fenêtre).
    // Le vrai garde-fou est l'inactivité : 5 min sans clic/touche -> l'état passe « idle », pas « worked ».
    if (dt <= 0 || !uid() || !onShift()) { emit(); return; }        // pas loggé / hors shift -> pas compté
    const st = effState();
    const { m, rec } = todayRec(); rec.name = uname();
    if (st === "break") { rec.brk += dt; if (S.breakType === "cafe") rec.cafe += dt; else if (S.breakType === "wc") rec.wc += dt; else if (S.breakType === "lunch") rec.lunch += dt; }
    else if (st === "idle") rec.idle += dt;
    else rec.worked += dt;
    rec.updatedAt = now; saveLocal(m); emit();
    if (st === "idle" && !S.idleNotified) { S.idleNotified = true; try { window.dispatchEvent(new CustomEvent("pl:va-inactive", { detail: { id: uid(), name: uname(), at: now } })); } catch (e) {} }
    if (st !== "idle") S.idleNotified = false;
  }

  const Clock = {
    note() { S.lastAct = Date.now(); },                                  // toute interaction = activité
    startShift() { S.shiftOn = true; S.ended = false; S.lastAct = Date.now(); S.lastTick = Date.now(); beginSession(); emit(); },
    endShift() { accumulate(); S.shiftOn = false; S.ended = true; S.breakType = null; S.sessionStart = 0; S.sessionBase = null; emit(); },
    startBreak(type) { if (S.breakType) return; accumulate(); S.breakType = type; S.breakStart = Date.now(); emit(); },
    endBreak() { accumulate(); S.breakType = null; S.lastAct = Date.now(); emit(); },  // reprendre = activité
    state() {
      const { rec } = todayRec();
      const b = S.sessionBase || { worked: 0, idle: 0, brk: 0 };
      const inSess = !!S.sessionStart;   // le compteur affiché = temps de la SESSION en cours (remis à 0 à chaque shift)
      return { st: effState(), onShift: onShift(), ended: S.ended, breakType: S.breakType, breakStart: S.breakStart, panels: S.panels, shiftOn: S.shiftOn, sessionStart: S.sessionStart,
        worked: inSess ? Math.max(0, rec.worked - b.worked) : 0, idle: inSess ? Math.max(0, rec.idle - b.idle) : 0, brk: inSess ? Math.max(0, rec.brk - b.brk) : 0,
        cafe: rec.cafe, wc: rec.wc, lunch: rec.lunch, sinceAct: Date.now() - S.lastAct };
    },
    // deltas de la SESSION courante (pour le rapport de fin de shift)
    session() {
      accumulate();
      const { rec } = todayRec(); const b = S.sessionBase || { worked: 0, idle: 0, brk: 0 };
      return { start: S.sessionStart || Date.now(), worked: Math.max(0, rec.worked - b.worked), idle: Math.max(0, rec.idle - b.idle), brk: Math.max(0, rec.brk - b.brk) };
    },
    all() { return load(); },
    sync() { return syncBackend(); },
    sub(cb) { subs.add(cb); return () => subs.delete(cb); },
  };
  window.ShiftClock = Clock;

  // présence : un panel de pilotage ouvert = « sur un phone » (dispatché par DeviceView)
  try { window.addEventListener("pl:panel-open", () => { accumulate(); S.panels++; S.ended = false; S.lastAct = Date.now(); S.lastTick = Date.now(); beginSession(); emit(); }); } catch (e) {}
  try { window.addEventListener("pl:panel-close", () => { accumulate(); S.panels = Math.max(0, S.panels - 1); emit(); }); } catch (e) {}
  // activité = clic / tap / touche (le simple survol souris ne compte pas)
  ["pointerdown", "keydown"].forEach(ev => { try { window.addEventListener(ev, () => { S.lastAct = Date.now(); }, true); } catch (e) {} });

  // chaque seconde : on comptabilise la seconde écoulée (persisté) + re-render
  try { setInterval(accumulate, 1000); } catch (e) {}
  try { setInterval(syncBackend, SAVE_MS); setTimeout(syncBackend, 3000); } catch (e) {}
  // au retour d'onglet : on comptabilise le temps passé caché (accumulate lit now - lastTick) ; à la mise
  // en arrière-plan : on flush + on synchronise. Ainsi le chrono continue à travers les changements d'onglet.
  try { document.addEventListener("visibilitychange", () => { accumulate(); if (document.hidden) syncBackend(); }); } catch (e) {}
})();

// ---- format court : secondes -> « 2h14 » / « 12m » / « 0m » ----
function shFmt(sec) {
  sec = Math.max(0, Math.floor(sec || 0));
  const h = Math.floor(sec / 3600), m = Math.floor((sec % 3600) / 60);
  return h ? (h + "h" + String(m).padStart(2, "0")) : (m + "m");
}
function shClock(sec) {   // « MM:SS » pour un chrono de pause court
  sec = Math.max(0, Math.floor(sec || 0));
  const m = Math.floor(sec / 60), s = sec % 60;
  return String(m).padStart(2, "0") + ":" + String(s).padStart(2, "0");
}
// chrono VIVANT à la seconde : « 0:03 » / « 12:07 » / « 1:05:09 » (pour la barre de shift en direct)
function shHms(sec) {
  sec = Math.max(0, Math.floor(sec || 0));
  const h = Math.floor(sec / 3600), m = Math.floor((sec % 3600) / 60), s = sec % 60;
  return (h ? h + ":" + String(m).padStart(2, "0") : String(m)) + ":" + String(s).padStart(2, "0");
}
// format précis pour les petites durées : « 45s » sous la minute, sinon « 12m » / « 2h14 »
// (évite qu'une pause / inactivité de moins d'une minute s'affiche « 0m » et paraisse ignorée)
function shFmtP(sec) { sec = Math.max(0, Math.floor(sec || 0)); return sec < 60 ? sec + "s" : shFmt(sec); }
window.shFmt = shFmt;
window.shFmtP = shFmtP;
window.shHms = shHms;

// ---- Rapports de fin de shift : immuables, keyés par (userId + fin), union à la synchro ----
const ShiftReports = (function () {
  const RKEY = "phonelabs.shift_reports";
  const load = () => { try { return JSON.parse(localStorage.getItem(RKEY)) || {}; } catch (e) { return {}; } };
  const save = (m) => { try { localStorage.setItem(RKEY, JSON.stringify(m)); } catch (e) {} };
  const rls = new Set(); const remit = () => rls.forEach(f => { try { f(); } catch (e) {} });
  const trim = (m) => { const keys = Object.keys(m).sort((a, b) => (m[b].end || 0) - (m[a].end || 0)).slice(0, 300); const o = {}; keys.forEach(k => o[k] = m[k]); return o; };
  const pushBackend = (m) => { try { if (window.Backend && window.Backend.saveStore && window.__FARM_USER__) window.Backend.saveStore("shift_reports", { savedAt: new Date().toISOString(), data: m }); } catch (e) {} };
  async function rsync() {
    if (!(window.Backend && window.Backend.getStore && window.__FARM_USER__)) return;
    let r = null; try { r = await window.Backend.getStore("shift_reports"); } catch (e) {}
    if (!r) return;
    const remote = (r.value && r.value.data) || {};
    const merged = trim({ ...remote, ...load() });   // union par id (un rapport ne se modifie jamais)
    save(merged); remit(); pushBackend(merged);
  }
  return {
    push(rep) { const m = load(); m[(rep.userId || "?") + "_" + rep.end] = rep; const t = trim(m); save(t); remit(); pushBackend(t); },
    list() { return Object.values(load()).sort((a, b) => (b.end || 0) - (a.end || 0)); },
    sync: rsync,
    sub(cb) { rls.add(cb); return () => rls.delete(cb); },
  };
})();
window.ShiftReports = ShiftReports;

// production réelle d'un VA depuis `sinceMs` (pour le rapport de session)
async function shComputeSessionReport(userId, name, sinceMs) {
  const isBan = (a) => (a.problem && a.problem.status === "ban") || /\bban\b/i.test(a.category || "");
  const nameL = (name || "").trim().toLowerCase();
  const mine = (id, nm) => (id && String(id) === String(userId)) || (!id && !!nameL && (nm || "").trim().toLowerCase() === nameL);
  let accounts = 0, phases = 0, plugs = 0, bans = 0;
  try { ((window.AccountCreationStore ? window.AccountCreationStore.list() : []) || []).forEach(a => { const at = Date.parse(a.saved_at || ""); if (!isNaN(at) && at >= sinceMs && mine(a.operator_id, a.operator)) { accounts++; if (isBan(a)) bans++; } }); } catch (e) {}
  try { const prog = (window.ParcoursProgress ? window.ParcoursProgress.all() : {}) || {}; Object.keys(prog).forEach(u => (prog[u].validations || []).forEach(v => { if (typeof v.at === "number" && v.at >= sinceMs && mine(v.by_id, v.by)) phases++; })); } catch (e) {}
  try {
    let cont = null; try { cont = (window.Backend && window.Backend.getContainers) ? await window.Backend.getContainers() : null; } catch (e) {}
    if (!cont) { try { cont = JSON.parse(localStorage.getItem("phonelabs.containers") || "{}"); } catch (e) { cont = {}; } }
    Object.keys(cont || {}).forEach(u => (Array.isArray(cont[u]) ? cont[u] : []).forEach(c => { if (c && c.plug && (c.plug_by || c.plug_by_id)) { const at = Date.parse(c.plug_at || c.created || ""); if (!isNaN(at) && at >= sinceMs && mine(c.plug_by_id, c.plug_by)) plugs++; } }));
  } catch (e) {}
  return { accounts, phases, plugs, bans };
}
window.shComputeSessionReport = shComputeSessionReport;

// Termine le shift : fige le RAPPORT de session (temps travaillé + inactivité + pauses + production réelle),
// l'envoie côté admin, PUIS stoppe le pointage (le compteur repart de 0 au prochain shift).
// Réutilisé par le bouton « Terminer » ET par la sortie du panel (quitter le panel = fin de shift).
async function shEndShift() {
  const C = window.ShiftClock; if (!C) return null;
  const u = (window.__FARM_USER__ && (window.__FARM_USER__.id || window.__FARM_USER__.name)) || "";
  const nm = (window.__FARM_USER__ && window.__FARM_USER__.name) || "";
  let sess = { start: Date.now(), worked: 0, idle: 0, brk: 0 };
  try { sess = C.session(); } catch (e) {}
  let prod = { accounts: 0, phases: 0, plugs: 0, bans: 0 };
  try { if (window.shComputeSessionReport) prod = await window.shComputeSessionReport(u, nm, sess.start); } catch (e) {}
  // on n'enregistre un rapport que si la session a réellement duré (> 10 s) — évite les rapports vides d'un aller-retour rapide
  if (((sess.worked || 0) + (sess.idle || 0) + (sess.brk || 0)) > 10) {
    try { window.ShiftReports && window.ShiftReports.push({ userId: u, name: nm, start: sess.start, end: Date.now(), worked: sess.worked, idle: sess.idle, brk: sess.brk, accounts: prod.accounts, phases: prod.phases, plugs: prod.plugs, bans: prod.bans }); } catch (e) {}
  }
  try { C.endShift(); } catch (e) {}
  return { ...sess, ...prod };
}
window.shEndShift = shEndShift;

function useShift() {
  const [, f] = React.useReducer(x => x + 1, 0);
  React.useEffect(() => { const u = window.ShiftClock ? window.ShiftClock.sub(f) : null; const iv = setInterval(f, 1000); return () => { if (u) u(); clearInterval(iv); }; }, []);
  return window.ShiftClock ? window.ShiftClock.state() : { st: "off", worked: 0, idle: 0, brk: 0 };
}

const SH_BREAKS = [
  { k: "cafe", emoji: "☕", label: "Café" },
  { k: "wc", emoji: "🚽", label: "Toilette" },
  { k: "lunch", emoji: "🍽️", label: "Déjeuner" },
];

// ============================================================
// ShiftBar — widget de pointage dans la barre du haut du panel
// ============================================================
function ShiftBar() {
  const { useState } = React;
  const s = useShift();
  const [menu, setMenu] = useState(false);
  const [confirmEnd, setConfirmEnd] = useState(false);
  const [ending, setEnding] = useState(false);
  const C = window.ShiftClock; if (!C) return null;

  // Terminer : on fige le RAPPORT de session (temps + production réelle), on l'envoie côté admin, puis reset du compteur.
  const doEndShift = async () => {
    if (ending) return; setEnding(true);
    try { if (window.shEndShift) await window.shEndShift(); else C.endShift(); } catch (e) {}
    setEnding(false); setConfirmEnd(false);
  };

  const stColor = { work: "#3fb950", idle: "#f0a020", break: "#9cc4f0", off: "var(--faint)" }[s.st] || "var(--faint)";
  const stLabel = { work: "🟢 Travaille", idle: "😴 Inactif", break: "En pause", off: "⚫ Hors shift" }[s.st] || "";
  const chip = { display: "inline-flex", alignItems: "center", gap: 4, fontSize: 11, fontWeight: 700, whiteSpace: "nowrap" };

  // EN PAUSE : bandeau dédié + bouton Reprendre
  if (s.st === "break") {
    const br = SH_BREAKS.find(b => b.k === s.breakType) || { emoji: "⏸", label: "Pause" };
    const dur = Math.floor((Date.now() - (s.breakStart || Date.now())) / 1000);
    return (
      <div style={{ display: "inline-flex", alignItems: "center", gap: 8, padding: "5px 6px 5px 12px", borderRadius: 10, background: "rgba(156,196,240,.12)", border: "1px solid rgba(156,196,240,.4)" }}>
        <span style={{ ...chip, color: "#9cc4f0" }}>{br.emoji} Pause {br.label.toLowerCase()} · <span className="mono">{shClock(dur)}</span></span>
        <button onClick={() => C.endBreak()} style={{ padding: "5px 11px", borderRadius: 8, border: "none", background: "#238636", color: "#fff", fontSize: 12, fontWeight: 800, cursor: "pointer" }}>▶ Reprendre</button>
      </div>
    );
  }

  const on = !!s.onShift;
  return (
    <div style={{ position: "relative", display: "inline-flex", alignItems: "center", gap: 11, padding: "5px 7px 5px 12px", borderRadius: 12, background: "var(--surface-2)", border: "1px solid var(--border)" }}>
      {/* statut : pastille + libellé */}
      <span style={{ display: "inline-flex", alignItems: "center", gap: 7, fontSize: 12, fontWeight: 800, color: stColor, whiteSpace: "nowrap" }}>
        <span style={{ width: 9, height: 9, borderRadius: 99, background: stColor, boxShadow: s.st === "work" ? "0 0 0 3px " + stColor + "30" : "none", flex: "none" }} />
        {{ work: "Travaille", idle: "Inactif", off: "Hors shift" }[s.st] || stLabel}
      </span>
      <span style={{ width: 1, height: 18, background: "var(--border)" }} />
      {/* compteurs de la SESSION en cours (repartent de 0 à chaque shift) */}
      <span style={{ display: "inline-flex", alignItems: "center", gap: 10, fontSize: 11, fontWeight: 700, whiteSpace: "nowrap" }}>
        <span style={{ color: "#3fb950" }} title="Temps travaillé sur ce shift (en direct)">⏱️ <span className="mono">{shHms(s.worked)}</span></span>
        <span style={{ color: "#f0a020" }} title="Temps inactif sur ce shift (5 min sans action = inactif)">😴 <span className="mono">{shHms(s.idle)}</span></span>
        <span style={{ color: "#9cc4f0" }} title="Pauses cumulées sur ce shift">☕ <span className="mono">{shHms(s.brk)}</span></span>
      </span>
      <span style={{ width: 1, height: 18, background: "var(--border)" }} />
      {/* bouton shift (Commencer / Terminer) + bouton pause, côte à côte */}
      {on
        ? <button onClick={() => setConfirmEnd(true)} title="Terminer le shift (arrête le pointage + rapport admin)" style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "6px 12px", borderRadius: 8, border: "1px solid rgba(248,81,73,.35)", background: "rgba(248,81,73,.08)", color: "#f87171", fontSize: 11.5, fontWeight: 800, cursor: "pointer" }}>⏹ Terminer</button>
        : <button onClick={() => C.startShift()} title={s.ended ? "Recommencer un shift (le compteur repart de 0)" : "Commencer mon shift (démarre le pointage)"} style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "6px 14px", borderRadius: 8, border: "none", background: "#238636", color: "#fff", fontSize: 12, fontWeight: 800, cursor: "pointer", boxShadow: "0 2px 8px rgba(35,134,54,.35)" }}>{s.ended ? "🔄 Recommencer un shift" : "▶ Commencer le shift"}</button>}
      <button onClick={() => setMenu(v => !v)} disabled={!on} title={on ? "Prendre une pause" : "Commence ton shift pour prendre une pause"}
        style={{ padding: "6px 12px", borderRadius: 8, border: "1px solid var(--border)", background: "var(--surface)", color: on ? "var(--text)" : "var(--faint)", fontSize: 11.5, fontWeight: 700, cursor: on ? "pointer" : "default" }}>⏸ Pause ▾</button>
      {menu && (
        <>
          <div onClick={() => setMenu(false)} style={{ position: "fixed", inset: 0, zIndex: 60 }} />
          <div style={{ position: "absolute", top: "calc(100% + 6px)", right: 0, zIndex: 61, background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, padding: 6, minWidth: 160, boxShadow: "0 12px 32px rgba(0,0,0,.4)" }}>
            {SH_BREAKS.map(b => (
              <button key={b.k} onClick={() => { C.startBreak(b.k); setMenu(false); }}
                style={{ display: "flex", alignItems: "center", gap: 9, width: "100%", padding: "8px 10px", borderRadius: 7, border: "none", background: "none", color: "var(--text)", fontSize: 13, fontWeight: 600, cursor: "pointer", textAlign: "left" }}
                onMouseEnter={e => e.currentTarget.style.background = "var(--surface-2)"} onMouseLeave={e => e.currentTarget.style.background = "none"}>
                <span style={{ fontSize: 15 }}>{b.emoji}</span>Pause {b.label.toLowerCase()}
              </button>
            ))}
          </div>
        </>
      )}

      {/* popup de confirmation « Terminer le shift » -> envoie le rapport côté admin */}
      {confirmEnd && (
        <div onClick={() => !ending && setConfirmEnd(false)} style={{ position: "fixed", inset: 0, background: "rgba(2,6,15,.72)", zIndex: 3000, display: "grid", placeItems: "center", padding: 16 }}>
          <div onClick={e => e.stopPropagation()} style={{ width: "min(400px,94vw)", background: "var(--bg,#0d1117)", border: "1px solid var(--border)", borderRadius: 16, padding: 22, textAlign: "left" }}>
            <div style={{ fontSize: 15.5, fontWeight: 800, marginBottom: 8 }}>Terminer le shift ?</div>
            <div style={{ fontSize: 12.5, color: "var(--muted)", lineHeight: 1.6, marginBottom: 12 }}>
              Ton pointage s'arrête et un <b>rapport de shift</b> est envoyé à l'admin. Récap de la session :
            </div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 14, fontSize: 13, fontWeight: 800, marginBottom: 18 }}>
              <span style={{ color: "#3fb950" }}>⏱️ {shHms(s.worked)}</span>
              <span style={{ color: "#f0a020" }}>😴 {shHms(s.idle)}</span>
              <span style={{ color: "#9cc4f0" }}>☕ {shHms(s.brk)}</span>
            </div>
            <div style={{ display: "flex", gap: 10, justifyContent: "flex-end" }}>
              <button onClick={() => setConfirmEnd(false)} disabled={ending} style={{ padding: "9px 16px", borderRadius: 9, background: "var(--surface-2)", border: "1px solid var(--border)", color: "var(--text)", fontWeight: 700, fontSize: 13, cursor: "pointer" }}>Annuler</button>
              <button onClick={doEndShift} disabled={ending} style={{ padding: "9px 18px", borderRadius: 9, border: "none", background: "#da3633", color: "#fff", fontWeight: 800, fontSize: 13, cursor: ending ? "default" : "pointer" }}>{ending ? "…" : "Oui, terminer"}</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
window.ShiftBar = ShiftBar;

// ============================================================
// ShiftDashboard — vue owner : temps de travail par VA (aujourd'hui)
// ============================================================
function ShiftDashboard() {
  const { useReducer, useEffect, useState } = React;
  const [, f] = useReducer(x => x + 1, 0);
  const [day, setDay] = useState(() => { const d = new Date(); return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0"); });
  useEffect(() => {
    const u = window.ShiftClock ? window.ShiftClock.sub(f) : null;
    const u2 = window.ShiftReports ? window.ShiftReports.sub(f) : null;
    if (window.ShiftClock) window.ShiftClock.sync();
    if (window.ShiftReports) window.ShiftReports.sync();
    const iv = setInterval(() => { if (window.ShiftClock) window.ShiftClock.sync(); if (window.ShiftReports) window.ShiftReports.sync(); }, 20000);
    return () => { if (u) u(); if (u2) u2(); clearInterval(iv); };
  }, []);
  const reports = (window.ShiftReports ? window.ShiftReports.list() : []).slice(0, 40);
  const all = window.ShiftClock ? window.ShiftClock.all() : {};
  const dayMap = all[day] || {};
  const rows = Object.keys(dayMap).map(uidk => ({ uid: uidk, ...dayMap[uidk] }))
    .filter(r => (r.worked || 0) + (r.idle || 0) + (r.brk || 0) > 30)   // ignore le bruit (< 30 s)
    .sort((a, b) => (b.worked || 0) - (a.worked || 0));
  const days = Object.keys(all).sort().reverse().slice(0, 30);

  const Card = window.Card || (({ children, pad }) => <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 14, padding: pad || 16 }}>{children}</div>);
  const th = { textAlign: "left", padding: "8px 10px", fontSize: 10.5, fontWeight: 700, color: "var(--faint)", textTransform: "uppercase", letterSpacing: ".04em", whiteSpace: "nowrap" };
  const td = { padding: "9px 10px", fontSize: 12.5, borderTop: "1px solid var(--border)", whiteSpace: "nowrap" };

  return (
    <div style={{ marginBottom: 16 }}>
      <Card pad={20}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: 12, flexWrap: "wrap" }}>
          <div>
            <div style={{ fontSize: 15, fontWeight: 800 }}>🕐 Temps de travail des VA</div>
            <div style={{ fontSize: 11.5, color: "var(--faint)", marginTop: 2 }}>Heures réelles travaillées · pauses · inactivité — on ne compte que le travail effectif</div>
          </div>
          <select value={day} onChange={e => setDay(e.target.value)} style={{ padding: "6px 10px", borderRadius: 8, border: "1px solid var(--border)", background: "var(--surface-2)", color: "var(--text)", fontSize: 12.5 }}>
            {days.length ? days.map(d => <option key={d} value={d}>{d}</option>) : <option value={day}>{day}</option>}
          </select>
        </div>
        {rows.length === 0 ? (
          <div style={{ fontSize: 12.5, color: "var(--faint)", padding: "18px 0", textAlign: "center" }}>Aucun pointage ce jour-là (le suivi démarre dès qu'un VA ouvre un panel de téléphone).</div>
        ) : (
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 620 }}>
              <thead><tr>
                <th style={th}>VA</th><th style={th}>🟢 Travaillé</th><th style={th}>😴 Inactif</th>
                <th style={th}>☕ Pauses</th><th style={th}>Détail pauses</th><th style={th}>Présence</th>
              </tr></thead>
              <tbody>
                {rows.map(r => {
                  const presence = (r.worked || 0) + (r.idle || 0) + (r.brk || 0);
                  return (
                    <tr key={r.uid}>
                      <td style={{ ...td, fontWeight: 700 }}>{r.name || String(r.uid).slice(0, 8)}</td>
                      <td style={{ ...td, color: "#3fb950", fontWeight: 800 }}>{shFmtP(r.worked)}</td>
                      <td style={{ ...td, color: (r.idle > 600 ? "#f0a020" : "var(--muted)") }}>{shFmtP(r.idle)}</td>
                      <td style={{ ...td, color: "#9cc4f0" }}>{shFmtP(r.brk)}</td>
                      <td style={{ ...td, color: "var(--faint)", fontSize: 11.5 }}>☕{shFmtP(r.cafe)} · 🚽{shFmtP(r.wc)} · 🍽️{shFmtP(r.lunch)}</td>
                      <td style={{ ...td, color: "var(--muted)" }}>{shFmtP(presence)}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </Card>

      {/* rapports de fin de shift : ce que chaque VA a effectué sur sa session */}
      <div style={{ height: 16 }} />
      <Card pad={20}>
        <div style={{ fontSize: 15, fontWeight: 800, marginBottom: 3 }}>📋 Rapports de fin de shift</div>
        <div style={{ fontSize: 11.5, color: "var(--faint)", marginBottom: 12 }}>Envoyé automatiquement quand un VA clique « Terminer » : temps + ce qu'il a produit sur la session.</div>
        {reports.length === 0 ? (
          <div style={{ fontSize: 12.5, color: "var(--faint)", padding: "14px 0", textAlign: "center" }}>Aucun rapport pour l'instant (un rapport arrive quand un VA termine son shift).</div>
        ) : (
          <div style={{ display: "grid", gap: 8 }}>
            {reports.map((rp, i) => {
              const when = rp.end ? new Date(rp.end).toLocaleString("fr-FR", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" }) : "";
              return (
                <div key={i} style={{ display: "flex", alignItems: "center", gap: 14, padding: "10px 12px", borderRadius: 10, background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }}>
                  <div style={{ minWidth: 130 }}>
                    <div style={{ fontWeight: 700, fontSize: 13 }}>{rp.name || String(rp.userId).slice(0, 8)}</div>
                    <div style={{ fontSize: 10.5, color: "var(--faint)" }}>fin {when}</div>
                  </div>
                  <div style={{ display: "flex", gap: 13, fontSize: 11.5, fontWeight: 700, flexWrap: "wrap", flex: 1 }}>
                    <span style={{ color: "#3fb950" }} title="Travaillé sur la session">⏱️ {shFmtP(rp.worked)}</span>
                    <span style={{ color: "#f0a020" }} title="Inactif (5 min sans action) sur la session">😴 {shFmtP(rp.idle)}</span>
                    <span style={{ color: "#9cc4f0" }} title="Pauses déclarées sur la session">☕ {shFmtP(rp.brk)}</span>
                    <span style={{ color: "var(--border)" }}>|</span>
                    <span title="Comptes créés">👤 {rp.accounts || 0}</span>
                    <span title="Phases validées">🧭 {rp.phases || 0}</span>
                    <span title="Plugs">🔌 {rp.plugs || 0}</span>
                    {(rp.bans || 0) > 0 && <span style={{ color: "#f87171" }} title="Bannis">🚫 {rp.bans}</span>}
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </Card>
    </div>
  );
}
window.ShiftDashboard = ShiftDashboard;
