// ============================================================
// Polycall — application : qualification + routeur par rôle
// ============================================================

const EMPTY_DRAFT = { code: null, devis: "", rappelDate: "", rappelHeure: "", sav: "" };
const nowHM = () => { const d = new Date(); return String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0"); };
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "density": "regular", "timer": true }/*EDITMODE-END*/;

/* ---------- barre d'action ---------- */
function ActionBar({ tab, setTab, draft, qualified, onReset, onQualify }) {
  const op = useOp();
  const cur = draft.code ? op.byCode(draft.code) : null;
  const ready = cur && (cur.needs !== "rappel" || (draft.rappelDate && draft.rappelHeure));

  if (qualified) {
    return (
      <div className="actionbar">
        <div className="actionbar-info"><I.check s={17} style={{ color: "var(--good)" }} /> Fiche déjà qualifiée et clôturée.</div>
        <div className="actions"><button className="btn btn-ghost" onClick={onReset}><I.history s={16} /> Rouvrir la fiche</button></div>
      </div>
    );
  }
  return (
    <div className="actionbar">
      <div className="actionbar-info">
        {cur
          ? <span className="sel-code"><ToneBadge tone={cur.tone}>{cur.label}</ToneBadge>
              {!ready && <span style={{ color: "var(--warn)", fontWeight: 600 }}>— précisez la date et l'heure</span>}</span>
          : <span><I.info s={15} /> Sélectionnez un code conclusion pour clôturer.</span>}
      </div>
      <div className="actions">
        {tab === "fiche"
          ? <button className="btn btn-dark" onClick={() => setTab("qualif")}>Passer à la qualification <I.arrowRight s={16} /></button>
          : <>
              {draft.code && <button className="btn btn-ghost" onClick={onReset}>Effacer</button>}
              <button className="btn btn-primary" disabled={!ready} onClick={onQualify}><I.checkBold s={16} /> Qualifier et clôturer</button>
            </>}
      </div>
    </div>
  );
}

/* ---------- bandeau fiche traitée ---------- */
function QualifiedBanner({ fiche }) {
  const op = useOp();
  const c = op.byCode(fiche.conclusion.code);
  const cc = fiche.conclusion;
  return (
    <div className="section span2" style={{ borderLeft: "3px solid var(--good)", maxWidth: 1100, marginBottom: 22 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 14, flexWrap: "wrap" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <span className="si" style={{ background: "var(--good-tint)", color: "var(--good)" }}><I.check s={16} /></span>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--ink-faint)", letterSpacing: ".08em", textTransform: "uppercase" }}>Code conclusion</div>
            <div style={{ fontSize: 15, fontWeight: 800 }}>{c ? c.label : cc.code}</div>
          </div>
        </div>
        <div style={{ marginLeft: "auto", display: "flex", gap: 22, fontSize: 12.5, color: "var(--ink-soft)" }}>
          {cc.rappelDate && <span><b style={{ color: "var(--ink)" }}>Rappel :</b> {cc.rappelDate} à {cc.rappelHeure}</span>}
          {cc.devis && <span><b style={{ color: "var(--ink)" }}>Réf. :</b> {cc.devis}</span>}
          <span><b style={{ color: "var(--ink)" }}>Clôturée à</b> {fiche.qualifiedAt}</span>
        </div>
      </div>
    </div>
  );
}

/* ---------- résultats de recherche ---------- */
function SearchResults({ query, clients, onPick, onClose }) {
  const q = query.trim().toLowerCase();
  if (!q) return null;
  const matchC = clients.filter((c) => [c.nom, c.prenom, c.societe, c.num, c.tel, c.ville].join(" ").toLowerCase().includes(q));
  return (
    <>
      <div style={{ position: "fixed", inset: 0, zIndex: 40 }} onClick={onClose} />
      <div style={{ position: "absolute", top: 56, left: 0, width: "100%", maxWidth: 460, background: "#fff", border: "1px solid var(--line)", borderRadius: 12, boxShadow: "var(--shadow-pop)", zIndex: 41, overflow: "hidden" }}>
        <div style={{ padding: "9px 14px", fontSize: 11, fontWeight: 700, color: "var(--ink-faint)", letterSpacing: ".06em", textTransform: "uppercase", borderBottom: "1px solid var(--line)" }}>
          Clients existants · {matchC.length}
        </div>
        {matchC.length === 0 && <div style={{ padding: 16, fontSize: 13, color: "var(--ink-soft)" }}>Aucun client trouvé. Créez une fiche vierge.</div>}
        {matchC.slice(0, 6).map((c) => (
          <button key={c.num} onClick={() => onPick(c)}
            style={{ display: "flex", alignItems: "center", gap: 12, width: "100%", textAlign: "left", border: "none", background: "transparent", padding: "11px 14px", borderBottom: "1px solid var(--line)" }}
            onMouseEnter={(e) => e.currentTarget.style.background = "var(--surface-2)"}
            onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
            <span style={{ width: 32, height: 32, borderRadius: 8, background: c.societe ? "var(--neutral-tint)" : "var(--info-tint)", color: c.societe ? "var(--neutral)" : "var(--info)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
              {c.societe ? <I.building s={16} /> : <I.user s={16} />}
            </span>
            <span style={{ flex: 1, minWidth: 0 }}>
              <span style={{ fontWeight: 700, fontSize: 13.5, display: "block" }}>{c.societe || (c.civilite + " " + c.prenom + " " + c.nom)}</span>
              <span style={{ fontSize: 11.5, color: "var(--ink-soft)" }}>{c.ville} · {c.tel}</span>
            </span>
            <span style={{ fontFamily: "var(--mono)", fontSize: 11, color: "var(--red)", background: "var(--red-tint)", padding: "2px 7px", borderRadius: 5 }}>{c.num}</span>
          </button>
        ))}
      </div>
    </>
  );
}

/* ====================== APP DE QUALIFICATION (agent / pilotage) ====================== */
function QualificationApp({ op, user, onLogout, onExit, exitLabel, updateFiches }) {
  const opCtx = useMemo(() => ({
    op, codes: op.codes, groups: groupsOf(op.codes),
    byCode: (c) => findCode(op.codes, c), forFlux: (f) => forFlux(op.codes, f),
  }), [op]);
  useEffect(() => { applyAccent(op.accent); }, [op.accent]);

  const fiches = useMemo(() => op.fiches.filter(isLive), [op.fiches]);
  const firstAttente = fiches.find((f) => f.status === "attente");
  const [selectedId, setSelectedId] = useState(firstAttente ? firstAttente.id : (fiches[0] && fiches[0].id));
  const [tab, setTab] = useState("attente");
  const [fluxFilter, setFluxFilter] = useState("tous");
  const [ficheTab, setFicheTab] = useState("fiche");
  const [drafts, setDrafts] = useState({});
  const [query, setQuery] = useState("");
  const [dash, setDash] = useState(false);
  const [toast, setToast] = useState(null);
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);

  const fiche = fiches.find((f) => f.id === selectedId) || null;
  const draft = (fiche && drafts[fiche.id]) || EMPTY_DRAFT;
  const setDraft = (u) => setDrafts((d) => ({ ...d, [fiche.id]: typeof u === "function" ? u(d[fiche.id] || EMPTY_DRAFT) : u }));

  const stats = useMemo(() => {
    const attente = fiches.filter((f) => f.status === "attente").length;
    const done = fiches.filter((f) => f.status === "traitee");
    const won = done.filter((f) => { const c = findCode(op.codes, f.conclusion.code); return c && c.tone === "good"; }).length;
    return { attente, traitees: done.length, taux: done.length ? Math.round(won / done.length * 100) : 0 };
  }, [fiches, op.codes]);

  const selectFiche = (id) => { setSelectedId(id); setFicheTab("fiche"); };
  const updateField = (key, val) => updateFiches((fs) => fs.map((f) => f.id === selectedId ? { ...f, fields: { ...f.fields, [key]: val } } : f));
  const updateType = (type) => updateFiches((fs) => fs.map((f) => f.id === selectedId ? { ...f, type } : f));
  const updateCanal = (canal) => {
    updateFiches((fs) => fs.map((f) => f.id === selectedId ? { ...f, canal } : f));
    if (fiche) PolycallAPI.updateFiche(selectedId, fiche.fields, fiche.type, canal);
  };
  const resetDraft = () => setDraft({ ...EMPTY_DRAFT });

  const qualify = () => {
    const conclusion = { code: draft.code, devis: draft.devis, rappelDate: draft.rappelDate, rappelHeure: draft.rappelHeure, sav: draft.sav };
    const t = nowHM();
    PolycallAPI.updateFiche(selectedId, fiche.fields, fiche.type);
    PolycallAPI.qualifyFiche(selectedId, conclusion);
    updateFiches((fs) => fs.map((f) => f.id === selectedId ? { ...f, status: "traitee", conclusion, qualifiedAt: t } : f));
    const c = findCode(op.codes, draft.code);
    setToast({ label: c ? c.label : draft.code }); setTimeout(() => setToast(null), 3200);
    const rest = fiches.filter((f) => f.status === "attente" && f.id !== selectedId);
    if (rest.length) { setSelectedId(rest[0].id); }
    setFicheTab("fiche");
  };
  const reopen = () => { PolycallAPI.reopenFiche(selectedId); updateFiches((fs) => fs.map((f) => f.id === selectedId ? { ...f, status: "attente", conclusion: null, qualifiedAt: null } : f)); };

  const newFiche = async (type = "entrant") => {
    const channel = type === "entrant" ? "Appel entrant" : "Appel sortant";
    const canal = DEFAULT_CHANNEL;
    const fields = blankFields();
    let id = fid();
    const r = await PolycallAPI.createFiche(op.id, type, canal, channel, fields);
    if (r && r.id) id = r.id;
    const nf = { id, type, status: "attente", waiting: "00:00", channel, canal, fields, conclusion: null, qualifiedAt: null, deletedAt: null };
    updateFiches((fs) => [nf, ...fs]); setTab("attente"); setSelectedId(id); setFicheTab("fiche");
  };
  const pickClient = async (c) => {
    const fields = { ...blankFields(), civilite: c.civilite, nom: c.nom, prenom: c.prenom, societe: c.societe, clientNum: c.num, adresse: c.adresse, cp: c.cp, ville: c.ville, tel: c.tel, email: c.email, matricule: c.matricule };
    const canal = DEFAULT_CHANNEL;
    let id = fid();
    const r = await PolycallAPI.createFiche(op.id, "entrant", canal, "Appel entrant", fields);
    if (r && r.id) id = r.id;
    const nf = { id, type: "entrant", status: "attente", waiting: "00:00", channel: "Appel entrant", canal, fields, conclusion: null, qualifiedAt: null, deletedAt: null };
    updateFiches((fs) => [nf, ...fs]); setQuery(""); setTab("attente"); setSelectedId(id); setFicheTab("fiche");
  };

  const qualified = fiche && fiche.status === "traitee";
  const exportNow = () => downloadFiches(fiches.filter((f) => f.status === "traitee"), op.codes, "polycall_" + op.id + "_traitees_" + new Date().toISOString().slice(0, 10) + ".csv");

  return (
    <OpCtx.Provider value={opCtx}>
      <div className="app" data-density={tw.density === "compact" ? "compact" : "regular"}>
        <div style={{ position: "relative" }}>
          <Topbar op={op} stats={stats} query={query} setQuery={setQuery} onOpenDash={() => setDash(true)}
            onExport={exportNow} user={user} onLogout={onLogout} onExit={onExit} exitLabel={exitLabel} />
          <SearchResults query={query} clients={op.clients} onPick={pickClient} onClose={() => setQuery("")} />
        </div>

        <div className="shell">
          <Queue fiches={fiches} tab={tab} setTab={setTab} selectedId={selectedId} onSelect={selectFiche}
            fluxFilter={fluxFilter} setFluxFilter={setFluxFilter} onNew={newFiche} />

          <div className="col-main" style={{ position: "relative" }}>
            {!fiche ? (
              <div className="main-empty">
                <OpMark op={op} s={52} radius={15} />
                <h2>Sélectionnez une fiche</h2>
                <p>Choisissez une fiche dans la file d'attente, ou créez-en une nouvelle.</p>
              </div>
            ) : (
              <>
                <FicheHeader fiche={fiche} tab={ficheTab} setTab={setFicheTab} onChangeType={updateType} onChangeCanal={updateCanal}
                  qualified={qualified} qualReady={!!draft.code} showTimer={tw.timer} />
                <div className="fiche-body">
                  {ficheTab === "fiche"
                    ? <>{qualified && <QualifiedBanner fiche={fiche} />}<FicheForm fiche={fiche} set={updateField} readOnly={qualified} /></>
                    : qualified
                      ? <div style={{ maxWidth: 1100 }}><QualifiedBanner fiche={fiche} /><div style={{ color: "var(--ink-soft)", fontSize: 13 }}>Cette fiche est clôturée. Rouvrez-la pour modifier la qualification.</div></div>
                      : <Qualification fiche={fiche} draft={draft} setDraft={setDraft} />}
                </div>
                <ActionBar tab={ficheTab} setTab={setFicheTab} draft={draft} qualified={qualified}
                  onReset={qualified ? reopen : resetDraft} onQualify={qualify} />
              </>
            )}
          </div>
        </div>

        {dash && <Dashboard fiches={fiches} codes={op.codes} op={op} onClose={() => setDash(false)} />}

        <TweaksPanel>
          <TweakSection label="Espace de travail" />
          <TweakRadio label="Densité" value={tw.density} options={["regular", "compact"]} onChange={(v) => setTweak("density", v)} />
          <TweakToggle label="Minuterie d'appel" value={tw.timer} onChange={(v) => setTweak("timer", v)} />
        </TweaksPanel>

        {toast && (
          <div className="toast-wrap">
            <div className="toast">
              <span className="ti"><I.checkBold s={13} /></span>
              Fiche qualifiée et clôturée
              <span className="tcode">{toast.label}</span>
            </div>
          </div>
        )}
      </div>
    </OpCtx.Provider>
  );
}

/* ---------- agent sans opération assignée ---------- */
function NoOp({ user, onLogout }) {
  return (
    <div className="app">
      <ConsoleBar user={user} onLogout={onLogout} icon="info" title="Aucune opération" accent="#b9760f" />
      <div className="main-empty" style={{ height: "calc(100vh - 60px)" }}>
        <I.info s={44} />
        <h2>Aucune opération assignée</h2>
        <p>Votre compte n'est rattaché à aucune opération. Contactez votre administrateur.</p>
      </div>
    </div>
  );
}

/* ---------- écran de chargement ---------- */
function BootSplash() {
  return (
    <div className="app" style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }}>
      <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 16, color: "var(--ink-faint)" }}>
        <Polymark s={46} />
        <div style={{ fontSize: 13, fontWeight: 600 }}>Chargement de Polycall…</div>
      </div>
    </div>
  );
}

/* ====================== ROUTEUR PAR RÔLE ====================== */
function Root() {
  const [operations, setOperations] = useState(() => cloneOperations());
  const [accounts, setAccounts] = useState(() => ACCOUNTS.map((a) => ({ ...a })));
  const [brand, setBrand] = useState({ logo: null });
  const [theme, setTheme] = useState(() => { try { return localStorage.getItem("polycall-theme") === "dark" ? "dark" : "light"; } catch (e) { return "light"; } });
  const [user, setUser] = useState(null);
  const [activeOpId, setActiveOpId] = useState(null);
  const [apiMode, setApiMode] = useState(false);
  const [booting, setBooting] = useState(true);

  useEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
    try { localStorage.setItem("polycall-theme", theme); } catch (e) {}
  }, [theme]);
  const toggleTheme = () => setTheme((t) => (t === "dark" ? "light" : "dark"));
  const brandValue = useMemo(() => ({ logo: brand.logo, theme, toggleTheme }), [brand.logo, theme]);

  // Détection du serveur : si présent, on charge l'état réel ; sinon mode démo.
  useEffect(() => { (async () => {
    const ok = await PolycallAPI.detect();
    setApiMode(ok);
    if (ok && PolycallAPI.hasToken()) {
      try {
        const me = await PolycallAPI.me();
        const data = await PolycallAPI.bootstrap();
        setOperations(data.operations); setAccounts(data.accounts || []); setBrand(data.brand || { logo: null }); setUser(me);
      } catch (e) { PolycallAPI.logout(); }
    }
    setBooting(false);
  })(); }, []);

  const updateOp = (id, fn) => setOperations((ops) => ops.map((o) => o.id === id ? fn(o) : o));

  const login = async (creds) => {
    if (apiMode) {
      const u = await PolycallAPI.login(creds.email, creds.password);   // peut lever une erreur
      const data = await PolycallAPI.bootstrap();
      setOperations(data.operations); setAccounts(data.accounts || []); setBrand(data.brand || { logo: null });
      setUser(u); setActiveOpId(null);
    } else { setUser(creds); setActiveOpId(null); }
  };
  const logout = () => { PolycallAPI.logout(); setUser(null); setActiveOpId(null); };
  const saveBrand = (b) => { setBrand(b); PolycallAPI.saveBrand(b.logo); };

  // hors opération (login / console / chooser) : accent plateforme par défaut
  useEffect(() => {
    const inOp = user && (user.role === "user" || activeOpId);
    if (!inOp) applyAccent(["#d12b2b", "#a81f1f", "#fbecec", "#f6dcdc"]);
  }, [user, activeOpId]);

  // admin avec une seule opération : entrée directe
  useEffect(() => {
    if (user && user.role === "admin" && !activeOpId) {
      const my = operations.filter((o) => user.operationIds.includes(o.id));
      if (my.length === 1) setActiveOpId(my[0].id);
    }
  }, [user, activeOpId, operations]);

  const renderScreen = () => {
    if (booting) return <BootSplash />;
    if (!user) return <LoginScreen accounts={accounts} operations={operations} onLogin={login} apiMode={apiMode} />;

    if (user.role === "user") {
      const op = operations.find((o) => o.id === user.operationIds[0]);
      if (!op) return <NoOp user={user} onLogout={logout} />;
      return <QualificationApp key={op.id} op={op} user={user} onLogout={logout}
        updateFiches={(fn) => updateOp(op.id, (o) => ({ ...o, fiches: fn(o.fiches) }))} />;
    }

    if (user.role === "visitor") {
      const op = operations.find((o) => o.id === user.operationIds[0]);
      if (!op) return <NoOp user={user} onLogout={logout} />;
      return <AdminWorkspace key={op.id} op={op} user={user} updateOp={(fn) => updateOp(op.id, fn)} onLogout={logout} />;
    }

    if (user.role === "super") {
      if (activeOpId) {
        const op = operations.find((o) => o.id === activeOpId);
        if (!op) { setActiveOpId(null); return null; }
        return <AdminWorkspace key={op.id} op={op} user={user} updateOp={(fn) => updateOp(op.id, fn)}
          onExit={() => setActiveOpId(null)} exitLabel="Retour à l'administration" onLogout={logout} />;
      }
      return <SuperAdminConsole user={user} operations={operations} setOperations={setOperations}
        accounts={accounts} setAccounts={setAccounts} brand={brand} setBrand={saveBrand} onEnterOp={setActiveOpId} onLogout={logout} />;
    }

    // admin
    if (!activeOpId) return <OperationChooser user={user} operations={operations} onPick={setActiveOpId} onLogout={logout} />;
    const op = operations.find((o) => o.id === activeOpId);
    if (!op) { setActiveOpId(null); return null; }
    return <AdminWorkspace key={op.id} op={op} user={user} updateOp={(fn) => updateOp(op.id, fn)}
      onExit={() => setActiveOpId(null)} exitLabel="Changer d'opération" onLogout={logout} />;
  };

  return <BrandCtx.Provider value={brandValue}>{renderScreen()}</BrandCtx.Provider>;
}

ReactDOM.createRoot(document.getElementById("root")).render(<Root />);
