// screens.jsx — écrans du parcours (hors Run et Confirm)
//
// CÂBLAGE (2026-08-07, passe « enlever le static ») : plus AUCUNE donnée de
// démonstration. Chaque écran lit le tenant et n'affiche que ce qu'il sait ;
// vide quand il ne sait rien. Règle appliquée partout : un champ visible est
// un champ PERSISTÉ — un champ qu'on saisit et qui se perd en silence est un
// mensonge d'interface. (Revenus nets et bénéfice ont été retirés : la base
// n'a pas encore de colonne pour eux.)
// Langue : chrome via I18N.t(), noms du métier via le lexique du domaine.
const { useState: useStateS, useEffect: useEffectS } = React;

/* ============ CONNEXION ============ */
function LoginScreen({ onLogin }) {
  const { t } = useLang();
  const [email, setEmail] = useStateS(G4M.email || "");
  const [password, setPassword] = useStateS("");
  const [busy, setBusy] = useStateS(false);
  const [err, setErr] = useStateS(null);

  const enter = async () => {
    setBusy(true); setErr(null);
    try {
      // AUTH BÊTA : le mot de passe échange contre un jeton — c'est lui qui
      // prouve l'identité à chaque appel. Le serveur résout le tenant depuis
      // le compte : le navigateur ne le choisit jamais.
      const me = await G4M.login(email.trim(), password);
      if (!me || !me.tenantId) throw new Error(t("Compte inconnu ou backend injoignable :") + " tenant absent");
      onLogin();
    } catch (e) {
      setErr(e.message);
    } finally { setBusy(false); }
  };

  return (
    <div className="login-wrap">
      <aside className="login-aside">
        <Logo size={34} />
        <div>
          <h1 className="login-claim">{t("Vos {demandes}, remplies pour vous.")}</h1>
          <p className="login-sub">{t("Grant4me lit le {formulaire} officiel, retrouve vos informations et le remplit. Vous n'avez qu'à confirmer le reste.")}</p>
          <div className="login-feats">
            <div className="login-feat"><Icon name="scan" size={22} /><span>{t("On repère chaque champ du {formulaire}, même les PDF complexes.")}</span></div>
            <div className="login-feat"><Icon name="auto" size={22} /><span>{t("On remplit automatiquement à partir de votre profil et vos documents.")}</span></div>
            <div className="login-feat"><Icon name="shield" size={22} /><span>{t("Vos données restent au Québec. Conforme à la Loi 25.")}</span></div>
          </div>
        </div>
        <p style={{ color: "#9fb3a5", fontSize: ".84rem" }}>{t("Un service pensé pour les PME")}</p>
      </aside>
      <div className="login-panel">
        <div className="login-card">
          <div className="screen-kick"><Icon name="lock" size={15} strokeWidth={2} /> {t("Connexion sécurisée")}</div>
          <h1>{t("Bienvenue")}</h1>
          <p className="muted" style={{ marginBottom: 20 }}>{t("Connectez-vous pour reprendre vos {demandes} ou en commencer une nouvelle.")}</p>
          <label className="pf-label" htmlFor="login-email">{t("Courriel")}</label>
          <input id="login-email" className="pf-input" value={email} placeholder={t("vous@entreprise.ca")}
            style={{ marginBottom: 14 }} autoComplete="username"
            onChange={(e) => setEmail(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && enter()} />
          <label className="pf-label" htmlFor="login-mdp">{t("Mot de passe")}</label>
          <input id="login-mdp" type="password" className="pf-input" value={password}
            style={{ marginBottom: 14 }} autoComplete="current-password"
            onChange={(e) => setPassword(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && enter()} />
          <Btn kind="primary" size="lg" full iconAfter="arrowR" onClick={enter} disabled={busy}>
            {busy ? t("Connexion…") : t("Se connecter")}
          </Btn>
          {err && <p style={{ color: "var(--danger)", fontSize: ".84rem", marginTop: 10 }}>
            {t("Compte inconnu ou backend injoignable :")} {err}</p>}
          <div className="oidc"><Icon name="shield" size={15} /> {t("Authentification gérée par votre identifiant unique (OIDC)")}</div>
          <div className="login-trust"><Icon name="shield" size={16} /> {t("Hébergement et traitement au Québec")}</div>
        </div>
      </div>
    </div>
  );
}

/* ============ TABLEAU DE BORD ============ */
const RUN_STATUS_UI = {
  done: { statut: "soumis", pct: 100 },
  awaiting_review: { statut: "a_completer", pct: 85 },
  awaiting_user: { statut: "a_completer", pct: 70 },
  filling: { statut: "a_completer", pct: 60 },
  inferring: { statut: "a_completer", pct: 40 },
  parsing: { statut: "a_completer", pct: 20 },
  pending: { statut: "brouillon", pct: 5 },
  failed: { statut: "brouillon", pct: 0 },
};

/* Billing card — tenant subscription status + Stripe Checkout / Portal. */
function BillingCard() {
  const { t } = useLang();
  const [sub, meta] = useG4M(() => G4M.mySubscription(), null, []);
  const [busy, setBusy] = useStateS(false);
  const [err, setErr] = useStateS(null);
  if (!meta.live || !sub) return null;
  if (sub.classe === "revendeur") return null;

  const active = !!sub.actif;
  const status = sub.stripeStatus || (active ? "active" : "inactive");

  const go = async (fn) => {
    setBusy(true); setErr(null);
    try {
      const r = await fn();
      if (r && r.url) window.location.href = r.url;
    } catch (e) {
      setErr(e.message);
    } finally { setBusy(false); }
  };

  return (
    <div className="card card-pad" style={{ gridColumn: "1 / -1" }}>
      <div className="section-h" style={{ marginTop: 0 }}>
        <span className="num"><Icon name="shield" size={13} strokeWidth={2.2} /></span>
        {t("Abonnement")} <span className="ln" />
      </div>
      <p className="muted" style={{ marginBottom: 12 }}>
        {active
          ? t("Votre abonnement est actif. Vous pouvez lancer des remplissages.")
          : t("L'abonnement est inactif. Activez la facturation pour lancer des remplissages.")}
      </p>
      <p style={{ fontSize: ".9rem", marginBottom: 14 }}>
        <b>{t("Statut")}:</b>{" "}
        <Pill tone={active ? "green" : "gold"} label={status} small />
      </p>
      <span style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
        {!active && (
          <Btn kind="primary" disabled={busy} onClick={() => go(() => G4M.createBillingCheckout())}>
            {busy ? t("Redirection…") : t("S'abonner (Stripe)")}
          </Btn>
        )}
        <Btn kind="secondary" disabled={busy} onClick={() => go(() => G4M.billingPortal())}>
          {t("Gérer la facturation")}
        </Btn>
      </span>
      {err && <p style={{ color: "var(--danger)", fontSize: ".84rem", marginTop: 10 }}>{err}</p>}
    </div>
  );
}

function DashboardScreen({ onNew, onOpen, onFirstVisit }) {
  const { t, lang } = useLang();
  const [runs, meta] = useG4M(() => G4M.runs(10), null, []);
  const [session] = useG4M(() => G4M.me(), null, []);
  // Premier passage d'un compte sans aucune demande : proposer le tutoriel.
  // Déclenchement UNIQUE gardé par un ref — l'ancienne condition
  // (`runs.length === 0` exact) ratait selon le minutage du chargement.
  // Dès que le serveur a répondu (meta.live) et qu'il n'y a aucune demande,
  // on propose, une seule fois.
  const tutoFired = React.useRef(false);
  useEffectS(() => {
    if (tutoFired.current || !meta.live) return;
    if (runs && runs.length > 0) return;   // a déjà des demandes → pas de tuto
    tutoFired.current = true;
    if (onFirstVisit) onFirstVisit();
  }, [meta.live, runs]);
  const demandes = (runs || []).map((r) => {
    const ui = RUN_STATUS_UI[r.status] || { statut: "brouillon", pct: 0 };
    return {
      id: r.id,
      titre: r.projectTitle || t("{demande} sans titre"),
      programme: r.companyName || "—",
      statut: ui.statut,
      pct: typeof r.progressPct === "number" && r.progressPct ? Math.round(r.progressPct) : ui.pct,
      maj: r.createdAt ? new Date(r.createdAt).toLocaleDateString(lang === "en" ? "en-CA" : "fr-CA") : "—",
    };
  });

  return (
    <div className="main main-full">
      <div className="shell-wide">
        <div className="dash-head">
          <div>
            {(session && session.companyName) &&
              <div className="screen-kick"><Icon name="building" size={15} strokeWidth={2} /> {session.companyName}</div>}
            <h1 className="screen-title" style={{ marginBottom: 6 }}>{t("Vos {demandes}")}</h1>
            <p className="muted">{t("Reprenez là où vous étiez, ou lancez une nouvelle {demande}.")}</p>
          </div>
          <span style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <LiveBadge meta={meta} />
            <Btn kind="primary" icon="plus" onClick={onNew}>{t("Nouvelle {demande}")}</Btn>
          </span>
        </div>
        <div className="dash-grid">
          <BillingCard />
          <div className="card new-card" onClick={onNew} role="button" tabIndex={0}
            onKeyDown={(e) => e.key === "Enter" && onNew()}>
            <span className="plus"><Icon name="plus" size={24} /></span>
            <div>
              <div style={{ fontWeight: 700, fontSize: "1.08rem", color: "var(--ink)" }}>{t("Commencer une nouvelle {demande}")}</div>
              <div className="muted" style={{ fontSize: ".9rem" }}>{t("Téléversez un {formulaire}. On s'occupe du reste.")}</div>
            </div>
          </div>
          {demandes.length === 0 && !meta.loading && (
            <div className="card card-pad" style={{ textAlign: "center", padding: "36px 30px" }}>
              <div style={{ fontFamily: "var(--serif)", fontSize: "1.15rem", fontWeight: 600, marginBottom: 6 }}>{t("Aucune {demande} pour l'instant")}</div>
              <p className="muted" style={{ maxWidth: 460, margin: "0 auto" }}>
                {t("Votre première {demande} commence par le {formulaire} à remplir. Téléversez-le : on lit les champs, on remplit ce qu'on peut, et on ne vous demande que le reste.")}
              </p>
            </div>
          )}
          {demandes.map((d, i) => (
            <div className="card demande" key={d.id || i} onClick={i === 0 ? onOpen : undefined}
              role="button" tabIndex={0} onKeyDown={(e) => e.key === "Enter" && i === 0 && onOpen()}>
              <div className="demande-main">
                <div className="demande-prog">{d.programme}</div>
                <div className="demande-title">{d.titre}</div>
                <div className="demande-meta">
                  <Pill status={d.statut} small />
                  <span><Icon name="clock" size={14} style={{ verticalAlign: "-2px" }} /> {t("Mis à jour")} : {d.maj}</span>
                </div>
              </div>
              <div className="demande-right">
                {d.statut !== "brouillon" || d.pct > 0 ? (
                  <div className="prog-mini">
                    <div className="prog-track"><div className="prog-fill" style={{ width: d.pct + "%" }} /></div>
                    <div className="prog-num">{d.pct}% {t("complété")}</div>
                  </div>
                ) : null}
                {i === 0 && <Btn kind="accent" iconAfter="arrowR" onClick={onOpen}>{t("Reprendre")}</Btn>}
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ============ ÉTAPE 1 — PROFIL ENTREPRISE ============ */
function PInput({ value, onChange, mono, locked, placeholder, ariaLabel, as, options }) {
  const cls = "pf-input" + (mono ? " mono" : "") + (locked ? " locked" : "");
  if (as === "select") {
    return (
      <select className={cls} value={value} aria-label={ariaLabel} onChange={(e) => onChange(e.target.value)}>
        {/* La VALEUR reste canonique (celle qu'on écrit en base) ; seul
            l'AFFICHAGE se traduit — sinon la langue de l'écran changerait la
            donnée enregistrée. */}
        {options.map((o) => <option key={o} value={o}>{o ? I18N.t(o) : "—"}</option>)}
      </select>
    );
  }
  return <input className={cls} value={value} placeholder={placeholder} aria-label={ariaLabel} readOnly={locked}
    onChange={(e) => onChange && onChange(e.target.value)} />;
}

function PField({ label, guide, required, children, span2 }) {
  return (
    <div className={"pf-field" + (span2 ? " span2" : "")}>
      <label className="pf-label">{label}{required && <span className="pf-req">*</span>}{guide && <HelpNote guide={guide} />}</label>
      {children}
    </div>
  );
}

function CompanyScreen({ onNext }) {
  const { t } = useLang();
  const [remote, meta] = useG4M(() => G4M.company(), null, []);
  const [session] = useG4M(() => G4M.me(), null, []);
  const [saving, setSaving] = useStateS(false);
  const [saveErr, setSaveErr] = useStateS(null);
  const caeSearch = useCaeSearch();

  // On part VIDE, toujours. Le profil du tenant remplit ce qu'il sait ; le
  // reste attend la personne. (L'ancien mode « démonstration » pré-remplissait
  // l'écran avec une entreprise fictive — un clic sur Enregistrer la
  // persistait. Supprimé, pas conditionné.)
  const [c, setC] = useStateS({ raison: "", neq: "", forme: "", bn: "",
    constitution: "", employes: "", revenus_bruts: "", secteur: "" });
  const [codes, setCodes] = useStateS([{ systeme: "CAE", code: "", libelle: "", principal: true }]);
  const [addr, setAddr] = useStateS("");
  const [contact, setContact] = useStateS({ nom: "", titre: "", courriel: "", tel: "" });
  const [needs, setNeeds] = useStateS([]);
  const [prodOff, setProdOff] = useStateS("");
  const [growth, setGrowth] = useStateS("");
  const [showMore, setShowMore] = useStateS(false);

  useEffectS(() => {
    if (!remote) return;
    setC({
      raison: remote.legalName || "", neq: remote.neq || "",
      forme: remote.legalForm || "", bn: remote.bnFederal || "",
      constitution: remote.dateConstitution || "",
      employes: remote.numEmployees != null ? String(remote.numEmployees) : "",
      revenus_bruts: remote.annualRevenueRange || "", secteur: remote.sector || "",
    });
    setAddr(remote.address || "");
    setProdOff(remote.productsOffered || "");
    setGrowth(remote.growthObjectives || "");
    setNeeds(Array.isArray(remote.financingNeeds) ? remote.financingNeeds : []);
    const saved = Array.isArray(remote.activityCodes) ? remote.activityCodes.filter((x) => x && x.code) : [];
    setCodes(saved.length ? saved.map((x) => ({ systeme: x.systeme || "CAE", code: x.code || "",
        libelle: x.libelle || "", principal: !!x.principal }))
      : [{ systeme: "CAE", code: remote.scianCode || "", libelle: remote.sector || "", principal: true }]);
    setContact({
      nom: remote.contactName || (session && session.fullName) || "",
      titre: remote.contactTitle || "",
      courriel: remote.email || (session && session.email) || "",
      tel: remote.contactPhone || "",
    });
  }, [remote && remote.id, session && session.email]);

  const set = (k, v) => setC((o) => ({ ...o, [k]: v }));
  const setCode = (i, k, v) => setCodes((cs) => cs.map((x, j) => j === i ? { ...x, [k]: v } : x));
  const setPrimary = (i) => setCodes((cs) => cs.map((x, j) => ({ ...x, principal: j === i })));
  const addCode = () => setCodes((cs) => [...cs, { systeme: "SCIAN", code: "", libelle: "", principal: false }]);
  const delCode = (i) => setCodes((cs) => cs.filter((_, j) => j !== i));
  const toggleNeed = (id) => setNeeds((n) => n.includes(id) ? n.filter((x) => x !== id) : [...n, id]);

  const save = async () => {
    if (!(remote && remote.id)) { setSaveErr(t("Compte inconnu ou backend injoignable :")); return; }
    setSaving(true); setSaveErr(null);
    try {
      const principal = codes.find((x) => x.principal) || codes[0] || {};
      await G4M.saveCompany(remote.id, {
        legalName: c.raison, neq: c.neq, sector: c.secteur, legalForm: c.forme,
        bnFederal: c.bn, numEmployees: parseInt(c.employes) || null,
        annualRevenueRange: c.revenus_bruts,
        dateConstitution: c.constitution || null,
        address: addr || null,
        scianCode: principal.code || null,
        activityCodes: codes.filter((x) => x.code || x.libelle),
        financingNeeds: needs,
        productsOffered: prodOff || null,
        growthObjectives: growth || null,
        contactNom: contact.nom || null, contactTitre: contact.titre || null,
        contactCourriel: contact.courriel || null, contactTel: contact.tel || null,
      });
    } catch (e) { setSaveErr(e.message); setSaving(false); return; }
    setSaving(false);
    onNext();
  };

  return (
    <ScreenShell kick={t("Étape {n} sur 6", { n: 1 })} icon="building" title={t("Votre profil d'entreprise")} hideLede>
      <p className="screen-lede" style={{ marginBottom: 24 }}>
        {t("Ces informations serviront à remplir ")}<b style={{ color: "var(--ink)" }}>{t("tous vos {formulaires}")}</b>{t(" : ce que vous saisissez ici, on ne vous le redemandera plus. ")}
        <b style={{ color: "var(--ink)" }}>{t("Vous ne savez pas où trouver une information ?")}</b> {t("Cliquez le « ? » à côté du champ.")}
      </p>
      <div className="card card-pad" style={{ background: "var(--green-bg)", borderColor: "var(--green-line)", display: "flex", gap: 14, alignItems: "flex-start", marginBottom: 6 }}>
        <Icon name="shield" size={20} />
        <p style={{ fontSize: ".92rem", color: "var(--ink-2)", lineHeight: 1.5 }}>
          {t("Ce profil ne se remplit ")}<b>{t("qu'une fois")}</b>{t(". Il sert à toutes vos {demandes} : plus vous le complétez, mieux on cible les bons {programmes} et plus le remplissage est précis.")}
        </p>
      </div>

      {/* --- Identité --- */}
      <div className="section-h"><span className="num">1</span> {t("Identité de l'entreprise")} <LiveBadge meta={meta} /> <span className="ln" /></div>
      <div className="card card-pad">
        <div className="pf-grid">
          <PField label={t("Raison sociale")} required span2>
            <PInput value={c.raison} onChange={(v) => set("raison", v)} ariaLabel={t("Raison sociale")} />
          </PField>
          <PField label={t("NEQ (Québec)")} guide={fieldGuide("neq")}>
            <PInput value={c.neq} mono onChange={(v) => set("neq", v)} ariaLabel="NEQ" />
            <span className="pf-hint" style={{ marginTop: 4 }}>{t("Tel qu'enregistré à votre dossier. Corrigez-le au besoin.")}</span>
          </PField>
          <PField label={t("Statut juridique")} guide={fieldGuide("forme")}>
            <PInput value={c.forme} onChange={(v) => set("forme", v)} ariaLabel={t("Statut juridique")} />
          </PField>
          <PField label={t("Numéro d'entreprise fédéral (NE / ARC)")} guide={fieldGuide("bn")}>
            <PInput value={c.bn} mono onChange={(v) => set("bn", v)} ariaLabel={t("Numéro d'entreprise fédéral (NE / ARC)")} />
          </PField>
          <PField label={t("Date de constitution (AAAA-MM-JJ)")} guide={fieldGuide("annee")}>
            {/* Une vraie date, pas une année : le moteur de dates refuse de
                deviner un mois. AAAA-MM-JJ est le format pivot. */}
            <PInput value={c.constitution} mono placeholder="2019-03-15"
              onChange={(v) => set("constitution", v)} ariaLabel={t("Date de constitution (AAAA-MM-JJ)")} />
          </PField>
          <PField label={t("Nombre d'employés")} guide={fieldGuide("employes")}>
            <PInput value={c.employes} mono onChange={(v) => set("employes", v)} ariaLabel={t("Nombre d'employés")} />
          </PField>
          <PField label={t("Revenus bruts (chiffre d'affaires)")} guide={fieldGuide("revenus_brut")}>
            <PInput as="select" value={c.revenus_bruts} onChange={(v) => set("revenus_bruts", v)} ariaLabel={t("Revenus bruts (chiffre d'affaires)")} options={REVENUE_RANGES} />
          </PField>
          <PField label={t("Secteur d'activité")} guide={fieldGuide("secteur")}>
            <PInput value={c.secteur} onChange={(v) => set("secteur", v)} ariaLabel={t("Secteur d'activité")} />
          </PField>
        </div>
      </div>

      {/* --- Adresse officielle --- */}
      <div className="section-h"><span className="num">2</span> {t("Adresses")} <HelpNote guide={fieldGuide("adresse")} /> <span className="ln" /></div>
      <div className="card card-pad">
        <div className="addr-item primary">
          <div>
            <div className="addr-lab">{t("Adresse officielle de l'entreprise")}<Pill status="auto" small label={t("Officielle")} /></div>
            <PInput value={addr} onChange={setAddr} ariaLabel={t("Adresse officielle de l'entreprise")} />
          </div>
          <span />
        </div>
        <p className="muted" style={{ fontSize: ".84rem", marginTop: 10 }}>
          {t("Seule l'adresse officielle est enregistrée à votre dossier pour l'instant.")}
        </p>
      </div>

      {/* --- Codes d'activité (multiples, persistés en jsonb) --- */}
      <div className="section-h"><span className="num">3</span> {t("Codes d'activité")} <HelpNote guide={fieldGuide("scian")} /> <span className="ln" /></div>
      <div className="card card-pad">
        <p className="muted" style={{ fontSize: ".9rem", marginBottom: 14 }}>{t("Une entreprise peut en avoir plusieurs. Tapez votre activité dans le libellé : on cherche dans le référentiel officiel et le code se remplit seul. Indiquez le principal.")}</p>
        <div className="codes-list">
          {codes.map((cd, i) => (
            <div className="code-row" key={i}>
              <PInput as="select" value={cd.systeme} onChange={(v) => setCode(i, "systeme", v)} ariaLabel="Référentiel" options={CODE_SYSTEMS} />
              <PInput value={cd.code} mono placeholder="2721" onChange={(v) => setCode(i, "code", v)} ariaLabel="Code" />
              <Autocomplete value={cd.libelle} placeholder={t("Rechercher une activité (ex. « ébénisterie », « génie »)…")} ariaLabel={t("Codes d'activité")}
                search={caeSearch} footHint={t("Référentiel officiel · 50 résultats max")}
                onChange={(v) => setCode(i, "libelle", v)}
                onPick={(m) => setCodes((cs) => cs.map((x, j) => j === i ? { ...x, code: m.code, libelle: m.libelle, systeme: "CAE" } : x))} />
              <label className="code-prim">
                <input type="radio" name="code-principal" checked={!!cd.principal} onChange={() => setPrimary(i)} /> {t("Principal")}
              </label>
              <button className="row-del" aria-label={t("Supprimer ce code")} onClick={() => delCode(i)} disabled={codes.length <= 1}>
                <Icon name="plus" size={18} strokeWidth={2} style={{ transform: "rotate(45deg)" }} />
              </button>
            </div>
          ))}
        </div>
        <button className="add-row" onClick={addCode}><Icon name="plus" size={16} strokeWidth={2.2} /> {t("Ajouter un code d'activité")}</button>
      </div>

      {/* --- Personne-ressource (signataire) --- */}
      <div className="section-h"><span className="num">4</span> {t("Personnes-ressources")} <span className="ln" /></div>
      <div className="card card-pad">
        <div className="pf-grid">
          <PField label={t("Nom")}><PInput value={contact.nom} ariaLabel={t("Nom")} onChange={(v) => setContact((x) => ({ ...x, nom: v }))} /></PField>
          <PField label={t("Fonction")}><PInput value={contact.titre} ariaLabel={t("Fonction")} onChange={(v) => setContact((x) => ({ ...x, titre: v }))} /></PField>
          <PField label={t("Courriel")}><PInput value={contact.courriel} ariaLabel={t("Courriel")} onChange={(v) => setContact((x) => ({ ...x, courriel: v }))} /></PField>
          <PField label={t("Téléphone")}><PInput value={contact.tel} mono ariaLabel={t("Téléphone")} onChange={(v) => setContact((x) => ({ ...x, tel: v }))} /></PField>
        </div>
        <span className="pf-verified" style={{ marginTop: 8 }}><Icon name="check" size={12} strokeWidth={2.6} /> {t("Signataire principal de la {demande}")}</span>
      </div>

      {/* --- Section facultative repliable (persistée elle aussi) --- */}
      <div className="collapse">
        <button className={"collapse-head" + (showMore ? " open" : "")} onClick={() => setShowMore((s) => !s)}>
          <span className="collapse-title">{t("Profil détaillé")}</span>
          <span className="collapse-opt">{t("Facultatif · améliore le ciblage")}</span>
          <Icon name="chevD" size={20} />
        </button>
        {showMore && (
          <div className="collapse-body">
            <PField label={t("Pour quels besoins cherchez-vous du financement ?")}>
              <div className="chips" style={{ marginTop: 4 }}>
                {FINANCING_NEEDS.map((n) => {
                  const on = needs.includes(n.id);
                  return (
                    <button key={n.id} className={"chip" + (on ? " on" : "")} onClick={() => toggleNeed(n.id)}>
                      <span className="chk">{on && <Icon name="check" size={11} strokeWidth={3} />}</span>{t(n.label)}
                    </button>
                  );
                })}
              </div>
            </PField>
            <div style={{ height: 20 }} />
            <div className="pf-grid">
              <PField label={t("Produits et services offerts")} span2>
                <textarea className="pf-input" rows={2} value={prodOff} onChange={(e) => setProdOff(e.target.value)} aria-label={t("Produits et services offerts")} />
              </PField>
              <PField label={t("Objectifs de croissance")} span2>
                <textarea className="pf-input" rows={2} value={growth} onChange={(e) => setGrowth(e.target.value)} aria-label={t("Objectifs de croissance")} />
              </PField>
            </div>
          </div>
        )}
      </div>

      {saveErr && <p style={{ color: "var(--danger)", fontSize: ".9rem", marginTop: 14 }}>
        {t("Enregistrement impossible :")} {saveErr}</p>}
      <WizNav onNext={save} nextLabel={saving ? t("Enregistrement…") : t("Enregistrer et continuer")} />
    </ScreenShell>
  );
}

/* ============ BILLING MODAL (shown on 402 or from profile) ============ */
function BillingModal({ open, onClose }) {
  const { t } = useLang();
  const [sub, meta] = useG4M(() => open ? G4M.mySubscription() : null, null, [open]);
  const [busy, setBusy] = useStateS(false);
  const [err, setErr] = useStateS(null);

  useEffectS(() => {
    if (!open) return;
    const esc = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", esc);
    return () => window.removeEventListener("keydown", esc);
  }, [open]);

  if (!open) return null;

  const active = sub && sub.actif;
  const status = (sub && sub.stripeStatus) || (active ? "active" : "inactive");

  const go = async (fn) => {
    setBusy(true); setErr(null);
    try {
      const r = await fn();
      if (r && r.url) window.location.href = r.url;
    } catch (e) { setErr(e.message); }
    finally { setBusy(false); }
  };

  return (
    <div className="billing-overlay" role="dialog" aria-label={t("Abonnement")} onClick={onClose}>
      <div className="billing-card card" onClick={(e) => e.stopPropagation()}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 14 }}>
          <h2 style={{ margin: 0, fontSize: "1.2rem" }}><Icon name="shield" size={20} /> {t("Abonnement")}</h2>
          <button className="btn btn-ghost" style={{ minHeight: 32, padding: "4px 10px" }} onClick={onClose} aria-label={t("Fermer")}>✕</button>
        </div>
        {!meta.live ? (
          <p className="muted">{t("Chargement…")}</p>
        ) : (
          <>
            <p style={{ fontSize: ".92rem", lineHeight: 1.6, marginBottom: 14 }}>
              {active
                ? t("Votre abonnement est actif. Vous pouvez lancer des remplissages.")
                : t("L'abonnement est inactif. Activez la facturation pour lancer des remplissages.")}
            </p>
            <p style={{ fontSize: ".9rem", marginBottom: 18 }}>
              <b>{t("Statut")}:</b>{" "}
              <Pill tone={active ? "green" : "gold"} label={status} small />
            </p>
            <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
              {!active && (
                <Btn kind="primary" disabled={busy} onClick={() => go(() => G4M.createBillingCheckout())}>
                  {busy ? t("Redirection…") : t("S'abonner (Stripe)")}
                </Btn>
              )}
              <Btn kind="secondary" disabled={busy} onClick={() => go(() => G4M.billingPortal())}>
                {t("Gérer la facturation")}
              </Btn>
            </div>
            {err && <p style={{ color: "var(--danger)", fontSize: ".84rem", marginTop: 10 }}>{err}</p>}
          </>
        )}
      </div>
    </div>
  );
}

/* ============ ÉTAPE 3 — TÉLÉVERSEMENT ============ */
function UploadScreen({ onNext, onBack, projectId, onRunStarted }) {
  const { t } = useLang();
  const [state, setState] = useStateS("idle"); // idle | uploading | done
  const [file, setFile] = useStateS(null);
  const [err, setErr] = useStateS(null);
  const [lang, setLang] = useStateS("");
  const [billingOpen, setBillingOpen] = useStateS(false);
  const inputRef = React.useRef(null);

  const pick = () => inputRef.current && inputRef.current.click();

  const isBillingError = (msg) => {
    return msg && (msg.toLowerCase().includes("subscription is inactive") || msg.toLowerCase().includes("402"));
  };

  const onFile = async (e) => {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    if (!projectId) { setErr(t("Aucun dossier ouvert. Connectez-vous d'abord.")); return; }
    setFile(f); setErr(null); setState("uploading");
    try {
      const b64 = await G4M.fileToBase64(f);
      const run = await G4M.startRun({
        projectId, sourcePdfBase64: b64, lang: lang || null, formDomain: null,
      });
      setState("done");
      if (onRunStarted) onRunStarted(run.id);
    } catch (e2) {
      const msg = e2.message || "";
      if (isBillingError(msg)) {
        setBillingOpen(true);
      }
      setErr(t(msg));
      setState("idle");
    }
  };

  return (
    <ScreenShell kick={t("Étape {n} sur 6", { n: 3 })} icon="upload" title={t("Téléversez le {formulaire} à remplir")}
      lede={t("Glissez le {formulaire} (PDF) que vous voulez déposer. On le lit immédiatement et on repère tous les champs à remplir.")}>
      <BillingModal open={billingOpen} onClose={() => setBillingOpen(false)} />
      <div className="card card-pad" style={{ background: "var(--surface-2)", marginBottom: 16, fontSize: ".92rem", color: "var(--ink-2)", lineHeight: 1.5 }}>
        <b>{t("Formulaires pris en charge : les PDF avec des cases à remplir intégrées.")}</b>
        {t(" Pour vérifier en 5 secondes : ouvrez le PDF et cliquez dans une case : si vous pouvez taper, c'est bon. Un scan ou un document à imprimer sera refusé immédiatement, sans frais d'analyse.")}
      </div>

      <input ref={inputRef} type="file" accept="application/pdf" style={{ display: "none" }} onChange={onFile} />

      {state !== "done" ? (
        <div className="card card-pad" style={{ borderStyle: "dashed", borderColor: "var(--line-2)", textAlign: "center", padding: "48px 30px", background: "var(--surface-2)" }}>
          {state === "idle" ? (
            <>
              <div style={{ width: 72, height: 72, borderRadius: "50%", background: "var(--surface)", border: "1px solid var(--line)", display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 18px", color: "var(--green)" }}>
                <Icon name="upload" size={32} />
              </div>
              <div style={{ fontFamily: "var(--serif)", fontSize: "1.3rem", fontWeight: 600, marginBottom: 6 }}>{t("Choisissez votre {formulaire}")}</div>
              <p className="muted" style={{ marginBottom: 16 }}>{t("PDF · jusqu'à 25 Mo · vos fichiers restent privés")}</p>
              <div style={{ display: "flex", gap: 10, justifyContent: "center", alignItems: "center", marginBottom: 18, flexWrap: "wrap" }}>
                <span className="muted" style={{ fontSize: ".86rem" }}>{t("Langue des questions :")}</span>
                <select className="pf-input" style={{ width: 190, minHeight: 40 }} value={lang}
                  aria-label={t("Langue")} onChange={(e) => setLang(e.target.value)}>
                  <option value="">{t("Automatique")}</option>
                  <option value="fr">Français</option>
                  <option value="en">English</option>
                </select>
              </div>
              <Btn kind="primary" icon="doc" onClick={pick}>{t("Choisir un {formulaire} PDF")}</Btn>
              {err && <p style={{ color: "var(--danger)", fontSize: ".88rem", marginTop: 14 }}>{err}</p>}
            </>
          ) : (
            <>
              <div className="spinner" style={{ width: 34, height: 34, borderWidth: 3, margin: "0 auto 18px" }} />
              <div style={{ fontFamily: "var(--serif)", fontSize: "1.2rem", fontWeight: 600 }}>{t("Lecture du document…")}</div>
              <p className="muted">{t("On ouvre {f}", { f: file ? file.name : "…" })}</p>
            </>
          )}
        </div>
      ) : (
        <div className="card card-pad" style={{ display: "flex", gap: 18, alignItems: "center", borderColor: "var(--green-line)", background: "var(--green-bg)" }}>
          <span style={{ width: 52, height: 52, borderRadius: 10, background: "var(--surface)", border: "1px solid var(--green-line)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--green)", flex: "0 0 auto" }}><Icon name="doc" size={26} /></span>
          <div style={{ flex: 1 }}>
            <div style={{ fontWeight: 600, color: "var(--ink)" }}>{file && file.name}</div>
            <div className="muted" style={{ fontSize: ".88rem" }}>{t("Remplissage démarré. Suivez le travail à l'étape suivante.")}</div>
          </div>
          <Pill status="auto" label={t("Lu avec succès")} />
        </div>
      )}
      <WizNav onNext={state === "done" ? onNext : null} onBack={onBack} nextLabel={t("Continuer")} nextDisabled={state !== "done"} />
    </ScreenShell>
  );
}

/* ============ ÉTAPE 6 — RÉSULTAT ============ */
function ResultScreen({ onBack, onHome, runId }) {
  const { t, L } = useLang();
  const [run] = useRunPolling(runId);
  const live = !!(runId && run);
  const docs = (live && run.requiredDocs ? run.requiredDocs : []).map((d) => ({
    nom: d.label,
    statut: d.mandatory ? "a_fournir" : "fourni",
    note: d.description || d.sourceInForm || "",
  }));
  const nAFournir = docs.filter((d) => d.statut === "a_fournir").length;

  const [dlErr, setDlErr] = useStateS(null);
  const download = async () => {
    // Le PDF vient du moteur, servi par le block — pas d'objet de stockage
    // exposé au navigateur.
    // Le PDF passe par la passerelle AUTHENTIFIÉE (/download/:runId), jamais
    // par l'API nue du moteur : celle-ci n'a pas d'auth et servirait le
    // document à quiconque connaît l'UUID du run.
    if (!(live && run.resultUrl && runId)) return;
    try {
      const r = await fetch("/download/" + runId, {
        headers: G4M.token ? { Authorization: "Bearer " + G4M.token } : {},
      });
      if (!r.ok) throw new Error("HTTP " + r.status);
      const blob = await r.blob();
      const a = document.createElement("a");
      a.href = URL.createObjectURL(blob);
      a.download = (run.projectTitle || "formulaire") + ".pdf";
      a.click();
      setTimeout(() => URL.revokeObjectURL(a.href), 30000);
    } catch (e) { setDlErr(e.message); }
  };

  return (
    <ScreenShell kick={t("Étape {n} sur 6", { n: 6 })} icon="check" title={t("Votre {demande} est prête à déposer")} hideLede>
      <div className="result-hero">
        <span className="seal"><Icon name="check" size={30} strokeWidth={2.4} /></span>
        <div>
          <h2 style={{ fontSize: "1.35rem", marginBottom: 4 }}>
            {live && run.detectedFields ? t("{formulaire} rempli ({n} champs)", { n: run.detectedFields }) : t("{formulaire} rempli")}
          </h2>
          <p style={{ color: "var(--ink-2)" }}>
            {live
              ? <>{t("Remplissage automatique : ")}<b>{run.pctAutoFilled ?? "—"} %</b>{t(" · validé par vous : ")}<b>{run.pctHumanValidated ?? "—"} %</b>{t(". Il vous reste à joindre quelques pièces.")}</>
              : t("Le PDF n'est pas encore prêt.")}
          </p>
        </div>
      </div>
      <div className="result-grid">
        <div>
          <div className="section-h"><span className="num"><Icon name="doc" size={13} strokeWidth={2.2} /></span> {t("Votre {formulaire} rempli")} <span className="ln" /></div>
          <div className="card card-pad" style={{ display: "flex", gap: 22, alignItems: "center", flexWrap: "wrap" }}>
            <div style={{ width: 150, flex: "0 0 auto" }}><FormPagePlaceholder label={t("aperçu (page 1)")} filled={9} /></div>
            <div style={{ flex: 1, minWidth: 220 }}>
              <div style={{ fontWeight: 600, fontSize: "1.05rem", marginBottom: 4 }}>{t("{formulaire} rempli")}</div>
              <p className="muted" style={{ fontSize: ".9rem", marginBottom: 16 }}>{t("PDF rempli, prêt à signer et à transmettre. Vous pourrez le rouvrir et le modifier à tout moment.")}</p>
              <Btn kind="accent" icon="download" size="lg" onClick={download} disabled={!live || !run.resultUrl}>{t("Télécharger le PDF rempli")}</Btn>
              {dlErr && <p style={{ color: "var(--danger)", fontSize: ".86rem", marginTop: 8 }}>{dlErr}</p>}
            </div>
          </div>
          <div className="section-h" style={{ marginTop: 34 }}><span className="num">→</span> {t("Comment soumettre")} <span className="ln" /></div>
          <ol className="next-steps">
            <li><span><b>{t("Rassemblez les {pieces}")}</b>{t(" listées à droite.")}</span></li>
            <li><span><b>{t("Faites signer le {formulaire}")}</b>{t(" par la personne autorisée de votre entreprise.")}</span></li>
            <li><span><b>{t("Déposez le tout")}</b>{t(" auprès de l'{organisme} avant l'échéance.")}</span></li>
          </ol>
        </div>
        <div>
          <div className="section-h"><span className="num">!</span> {t("{pieces} à joindre")} <LiveBadge meta={{ loading: false, live }} /> <span className="ln" /></div>
          <div className="card card-pad">
            <div className="doclist">
              {docs.map((d, i) => (
                <div className="docitem" key={i}>
                  <span className={"docitem-check " + d.statut}>
                    <Icon name={d.statut === "fourni" ? "check" : "plus"} size={15} strokeWidth={2.4} />
                  </span>
                  <div className="docitem-main">
                    <div className="docitem-nom">{d.nom}</div>
                    <div className="docitem-note">{d.note}</div>
                  </div>
                </div>
              ))}
            </div>
            <div style={{ marginTop: 16, paddingTop: 16, borderTop: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 8, fontSize: ".88rem", color: "var(--ink-2)", fontWeight: 600 }}>
              <Pill status="a_fournir" small label={t("{n} à rassembler", { n: nAFournir + " " + L(nAFournir > 1 ? "pieces" : "piece") })} />
            </div>
          </div>
        </div>
      </div>
      <div className="wiz-nav">
        <Btn kind="ghost" icon="arrowL" onClick={onBack}>{t("Retour")}</Btn>
        <Btn kind="secondary" onClick={onHome}>{t("Revenir au tableau de bord")}</Btn>
      </div>
    </ScreenShell>
  );
}

/* ============ helpers de mise en page ============ */
function ScreenShell({ kick, icon, title, lede, hideLede, children }) {
  return (
    <div className="main">
      <div className="shell-narrow" style={{ maxWidth: title && title.length > 40 ? 980 : 880 }}>
        <div className="screen-kick"><Icon name={icon} size={15} strokeWidth={2} /> {kick}</div>
        <h1 className="screen-title">{title}</h1>
        {!hideLede && lede && <p className="screen-lede" style={{ marginBottom: 30 }}>{lede}</p>}
        {children}
      </div>
    </div>
  );
}

function WizNav({ onNext, onBack, nextLabel, nextStrong, nextDisabled }) {
  return (
    <div className="wiz-nav">
      {onBack ? <Btn kind="ghost" icon="arrowL" onClick={onBack}>{I18N.t("Retour")}</Btn> : <span />}
      {onNext !== undefined && (
        <Btn kind="primary" iconAfter="arrowR" onClick={onNext} disabled={nextDisabled || !onNext}>
          {nextLabel || I18N.t("Continuer")}{nextStrong ? <strong style={{ fontWeight: 700 }}>{nextStrong}</strong> : ""}
        </Btn>
      )}
    </div>
  );
}

Object.assign(window, { LoginScreen, DashboardScreen, CompanyScreen, UploadScreen, ResultScreen, ScreenShell, WizNav, BillingModal });
