// AXLU — main app shell: routing, sidebar, command palette, tweaks

const NAV = [
  { id: "dashboard", label: "Tableau de bord", icon: "dashboard", emoji: "\uD83C\uDFE0", href: "#/dashboard" },
  { id: "catalog",   label: "Catalogue",       icon: "catalog",   emoji: "\uD83D\uDCDA", href: "#/catalog" },
  { id: "suppliers", label: "Fournisseurs",    icon: "plug",      emoji: "\uD83D\uDD0C", href: "#/suppliers" },
  { id: "syncs",     label: "Synchronisations",icon: "sync",      emoji: "\uD83D\uDD04", href: "#/syncs" },
  { id: "categories",label: "Catégories",      icon: "tag",       emoji: "\uD83C\uDFF7\uFE0F", href: "#/categories" },
  { id: "pricing",   label: "Pricing",         icon: "coin",      emoji: "\uD83D\uDCB0", href: "#/pricing" },
  { id: "shopify",   label: "Publications",    icon: "cart",      emoji: "\uD83D\uDED2", href: "#/shopify" },
  { id: "logs",      label: "Logs & audit",    icon: "log",       emoji: "\uD83D\uDCDC", href: "#/logs" },
  { id: "admin",     label: "Utilisateurs",    icon: "users",     emoji: "\uD83D\uDC65", href: "#/admin" },
];

function useHashRoute() {
  const [hash, setHash] = useState(window.location.hash || "#/dashboard");
  useEffect(() => {
    const h = () => setHash(window.location.hash || "#/dashboard");
    window.addEventListener("hashchange", h);
    return () => window.removeEventListener("hashchange", h);
  }, []);
  const navigate = useCallback((to) => { window.location.hash = to.replace(/^#/, ""); }, []);
  return { hash, navigate };
}

function parseRoute(hash) {
  const [path, query] = hash.replace(/^#/, "").split("?");
  const parts = path.split("/").filter(Boolean);
  const params = {};
  if (query) query.split("&").forEach((p) => { const [k, v] = p.split("="); params[k] = decodeURIComponent(v || ""); });
  return { parts, params };
}

// ─── Mandatory update gate ─────────────────────────────────────────────
// When the main process reports an update, this centred overlay blocks the
// entire app: a progress bar while it downloads, then a « Redémarrer »
// button. The app cannot be used until the update has been applied.
function UpdateGate() {
  const [st, setSt] = useState(null);
  const [restarting, setRestarting] = useState(false);
  useEffect(() => {
    if (!window.axlu || !window.axlu.update) return;
    // Pick up an update whose events fired before this component mounted.
    try {
      window.axlu.update.status().then((s) => { if (s) setSt(s); });
    } catch (e) { /* ignore */ }
    return window.axlu.update.onStatus((s) => setSt(s));
  }, []);
  if (!st || (st.state !== "downloading" && st.state !== "ready")) return null;
  const ready = st.state === "ready";
  const pct = ready ? 100 : (typeof st.percent === "number" ? st.percent : 0);
  return (
    <div className="fixed inset-0 z-[9999] flex items-center justify-center anim-fade"
         style={{ background: "rgba(0,0,0,.6)" }}>
      <div className="surface border rounded-xl anim-scale"
           style={{ borderColor: "var(--border)", boxShadow: "var(--shadow-lg)", width: 440 }}>
        <div className="p-6">
          <div className="text-[15px] font-semibold accent-fg">
            {ready ? `Mise à jour ${st.version || ""} prête` : "Mise à jour en cours…"}
          </div>
          <div className="text-[12.5px] text-muted mt-1.5 leading-relaxed">
            {ready
              ? "L'application doit redémarrer pour appliquer la mise à jour. Cliquez sur « Redémarrer maintenant » pour continuer."
              : "Une nouvelle version est disponible et se télécharge. Merci de patienter…"}
          </div>
          <div className="mt-4 h-2.5 rounded-full overflow-hidden sunken">
            <div style={{ width: pct + "%", height: "100%", background: "var(--accent)", transition: "width .3s ease" }}/>
          </div>
          <div className="text-[11px] text-subtle mono mt-1 text-right">{pct} %</div>
          {ready && (
            <div className="mt-4 flex justify-end">
              <Button variant="primary" leftIcon="refresh" disabled={restarting}
                      onClick={() => { setRestarting(true); try { window.axlu.update.restartNow(); } catch (e) { /* ignore */ } }}>
                {restarting ? "Redémarrage…" : "Redémarrer maintenant"}
              </Button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// Bandeau global "import en cours" — visible partout pendant qu'un import (Job Scaleway)
// tourne, pour qu'un collaborateur sache que ça travaille (et ne reclique pas).
function ImportBanner() {
  useAxluStore();
  if (!(window.AxluData && window.AxluData.__importRunning)) return null;
  return (
    <div className="flex items-center gap-2.5 px-4 py-2 text-[13px] font-medium" style={{ background: "var(--accent)", color: "#fff" }}>
      <Icon name="sync" size={15} className="animate-spin"/>
      <span>Import en cours — le catalogue se met à jour automatiquement (~1-2 min).</span>
    </div>
  );
}

function App() {
  const auth = useAuth();
  const logged = !!auth.user;
  const { hash, navigate } = useHashRoute();
  const { parts, params } = parseRoute(hash);
  let root = parts[0] || "dashboard";
  const [ownPwdOpen, setOwnPwdOpen] = useState(false);

  // Auto-reset localStorage if ?reset=1 in URL
  useEffect(() => {
    const urlParams = new URLSearchParams(window.location.search);
    if (urlParams.get('reset') === '1') {
      localStorage.removeItem('axlu.state.v3');
      console.log('✓ Cleared localStorage.axlu.state.v3, reloading...');
      window.location.href = window.location.pathname;
    }
  }, []);

  // Route guard — if the current user can't access this section, fall back to dashboard.
  useEffect(() => {
    if (!logged) return;
    if (!window.AxluStore.can("nav:" + root)) {
      const fallback = window.AxluStore.can("nav:dashboard") ? "#/dashboard" : "#/dashboard";
      if (hash !== fallback) navigate(fallback);
    }
  }, [logged, root, hash]);

  // Tweaks
  const [tweaks, setTweak] = useTweaks(window.__TWEAK_DEFAULTS || {
    theme: "light", density: "comfort", accent: "indigo", sidebarCollapsed: false,
  });

  useEffect(() => {
    document.documentElement.classList.toggle("dark", tweaks.theme === "dark");
    document.body.dataset.density = tweaks.density;
    const accents = {
      indigo: { c: "#4338ca", h: "#3730a3", bg: "#eef2ff", bgh: "#e0e7ff" },
      teal:   { c: "#0f766e", h: "#115e59", bg: "#f0fdfa", bgh: "#ccfbf1" },
      amber:  { c: "#b45309", h: "#92400e", bg: "#fffbeb", bgh: "#fef3c7" },
    };
    const a = accents[tweaks.accent] || accents.indigo;
    document.documentElement.style.setProperty("--accent", a.c);
    document.documentElement.style.setProperty("--accent-hover", a.h);
    if (tweaks.theme !== "dark") {
      document.documentElement.style.setProperty("--accent-bg", a.bg);
      document.documentElement.style.setProperty("--accent-bg-hover", a.bgh);
    }
  }, [tweaks]);

  // Command palette
  const [paletteOpen, setPaletteOpen] = useState(false);
  useEffect(() => {
    const k = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); setPaletteOpen(true); }
      if (e.key === "Escape") setPaletteOpen(false);
    };
    window.addEventListener("keydown", k);
    return () => window.removeEventListener("keydown", k);
  }, []);

  // Persist state synchronously when the window is about to close — main waits
  // for flushDone() before actually closing, so the latest edit is never lost.
  useEffect(() => {
    if (!window.axlu || typeof window.axlu.onFlushBeforeClose !== "function") return;
    return window.axlu.onFlushBeforeClose(() => {
      try { if (window.AxluStore && window.AxluStore.flush) window.AxluStore.flush(); } catch (e) { /* ignore */ }
      try { window.axlu.flushDone(); } catch (e) { /* ignore */ }
    });
  }, []);

  // A scheduled sync (Windows task) that fires while the app is open is
  // routed here — run a full background sync in the running window.
  useEffect(() => {
    if (!window.axlu || typeof window.axlu.onTriggerSync !== "function") return;
    let running = false;
    return window.axlu.onTriggerSync(async () => {
      if (running) return;
      running = true;
      try {
        if (typeof window.__axluToast === "function") window.__axluToast("Synchronisation planifiée — en cours…", { tone: "info" });
        const suppliers = (window.AxluData && window.AxluData.SUPPLIERS) || [];
        let total = 0;
        for (let i = 0; i < suppliers.length; i++) {
          try { const r = await runSupplierFeedsInOrder(suppliers[i], { dueOnly: true }); if (r) total += (r.ran || 0); }
          catch (e) { console.warn("[AXLU] scheduled sync — supplier failed", e); }
        }
        if (typeof window.__axluToast === "function") window.__axluToast(`Synchronisation planifiée terminée — ${total} flux`, { tone: "success" });
      } catch (e) {
        console.error("[AXLU] scheduled sync error", e);
      } finally {
        running = false;
      }
    });
  }, []);

  if (!logged) return <LoginScreen onLogin={() => navigate("#/dashboard")}/>;

  let screen;
  if (root === "dashboard") screen = <Dashboard navigate={navigate}/>;
  else if (root === "catalog") screen = <CatalogList navigate={navigate} initialStatus={params.status} initialMarginMax={params.marginMax} initialLastImport={params.lastImport}/>;
  else if (root === "products" && parts[1]) screen = <ProductDetail productId={parts[1]} navigate={navigate}/>;
  else if (root === "suppliers" && parts[1]) screen = <SupplierDetail supplierId={parts[1]} navigate={navigate}/>;
  else if (root === "suppliers") screen = <SuppliersList navigate={navigate}/>;
  else if (root === "syncs" && parts[1]) screen = <SyncDetail syncId={parts[1]} navigate={navigate}/>;
  else if (root === "syncs") screen = <SyncsList navigate={navigate} initialStatus={params.status}/>;
  else if (root === "categories") screen = <CategoriesScreen initialFilter={params.filter}/>;
  else if (root === "pricing") screen = <PricingScreen/>;
  else if (root === "shopify") screen = <ShopifyScreen/>;
  else if (root === "logs") screen = <LogsScreen/>;
  else if (root === "admin") screen = <AdminUsersScreen/>;
  else screen = <Dashboard navigate={navigate}/>;

  return (
    <ToastProvider>
      <div className="flex min-h-screen" style={{ minWidth: 1280 }}>
        <Sidebar collapsed={tweaks.sidebarCollapsed} setCollapsed={(v) => setTweak("sidebarCollapsed", v)}
                 currentRoot={root} navigate={navigate} onOpenPalette={() => setPaletteOpen(true)}
                 currentUser={auth.user}
                 onChangeOwnPassword={() => setOwnPwdOpen(true)}
                 onLogout={() => { window.AxluStore.dispatch("auth.logout"); navigate("#/dashboard"); }}/>
        <main className="flex-1 min-w-0" style={{ background: "var(--bg)" }}>
          <ImportBanner/>
          {screen}
        </main>
      </div>
      <CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} navigate={navigate}/>
      <TweaksPanel title="Tweaks">
        <TweakSection label="Apparence"/>
        <TweakRadio label="Thème" value={tweaks.theme} onChange={(v) => setTweak("theme", v)}
                    options={[{ value: "light", label: "Clair" }, { value: "dark", label: "Sombre" }]}/>
        <TweakRadio label="Accent" value={tweaks.accent} onChange={(v) => setTweak("accent", v)}
                    options={[
                      { value: "indigo", label: "Indigo" },
                      { value: "teal", label: "Teal" },
                      { value: "amber", label: "Ambre" },
                    ]}/>
        <TweakSection label="Densité"/>
        <TweakRadio label="Tableaux" value={tweaks.density} onChange={(v) => setTweak("density", v)}
                    options={[
                      { value: "dense", label: "Dense" },
                      { value: "compact", label: "Compact" },
                      { value: "comfort", label: "Confort" },
                    ]}/>
        <TweakSection label="Layout"/>
        <TweakToggle label="Sidebar repliée" value={tweaks.sidebarCollapsed} onChange={(v) => setTweak("sidebarCollapsed", v)}/>
      </TweaksPanel>
      <PasswordChangeModal mode="force" open={!!auth.mustChangePassword} userId={auth.user?.id}/>
      <PasswordChangeModal mode="own"   open={ownPwdOpen} userId={auth.user?.id}
                           onClose={() => setOwnPwdOpen(false)}
                           onDone={() => setOwnPwdOpen(false)}/>
    </ToastProvider>
  );
}

// ─── Password change modal (force after key login OR voluntary) ───────
function PasswordChangeModal({ open, mode, userId, onClose, onDone }) {
  const [current, setCurrent] = useState("");
  const [pwd, setPwd] = useState("");
  const [pwd2, setPwd2] = useState("");
  const [error, setError] = useState(null);
  const toast = useToast();

  useEffect(() => {
    if (open) { setCurrent(""); setPwd(""); setPwd2(""); setError(null); }
  }, [open]);

  const checks = window.AxluStore.checkPassword(pwd);
  const matches = pwd.length > 0 && pwd === pwd2;
  const valid = checks.length && checks.upper && checks.digit && checks.special && matches && (mode === "force" || current.length > 0);

  const submit = async (e) => {
    e?.preventDefault();
    if (!valid) return;
    const payload = { id: userId, password: pwd };
    if (mode === "own") payload.currentPassword = current;
    const res = (await window.AxluStore.dispatch("auth.changePassword", payload)) || {};
    if (!res.ok) { setError(res.error || "Échec"); return; }
    toast("Mot de passe enregistré", { tone: "success" });
    if (mode === "own" && onDone) onDone();
  };

  if (!open) return null;
  return (
    <Modal open={open} onClose={onClose} dismissible={mode === "own"}
           zIndex={mode === "force" ? 400 : 150}
           title={mode === "force" ? "Définir votre mot de passe" : "Modifier mon mot de passe"}
           width={460}
           footer={<>
             {mode === "own" && <Button variant="ghost" onClick={onClose}>Annuler</Button>}
             <Button variant="primary" onClick={submit} disabled={!valid}>Enregistrer</Button>
           </>}>
      <form onSubmit={submit} className="space-y-3">
        {mode === "force" && (
          <div className="text-[13px] text-muted leading-relaxed">
            Connexion par clé réussie. Définissez maintenant un mot de passe — il sera demandé à vos prochaines connexions.
          </div>
        )}
        {mode === "own" && (
          <Field label="Mot de passe actuel">
            <Input type="password" value={current} onChange={(e) => { setCurrent(e.target.value); setError(null); }} size="lg" autoFocus/>
          </Field>
        )}
        <Field label="Nouveau mot de passe">
          <Input type="password" value={pwd} onChange={(e) => { setPwd(e.target.value); setError(null); }} size="lg" autoFocus={mode === "force"}/>
        </Field>
        <Field label="Confirmer le mot de passe">
          <Input type="password" value={pwd2} onChange={(e) => { setPwd2(e.target.value); setError(null); }} size="lg"/>
        </Field>
        <div className="rounded-md sunken px-3 py-2 space-y-1 text-[12px]">
          <div className="text-[11px] uppercase tracking-wider text-subtle font-semibold mb-1">Exigences</div>
          <PwdRule ok={checks.length}  text="Au moins 8 caractères"/>
          <PwdRule ok={checks.upper}   text="Au moins une lettre majuscule"/>
          <PwdRule ok={checks.digit}   text="Au moins un chiffre"/>
          <PwdRule ok={checks.special} text="Au moins un caractère spécial : @ ! . , ; : /"/>
          <PwdRule ok={matches}        text="Les deux saisies correspondent"/>
        </div>
        {error && <div className="text-[12.5px]" style={{ color: "#b91c1c" }}>{error}</div>}
        {/* Hidden submit so Enter triggers the form */}
        <button type="submit" style={{ display: "none" }} tabIndex={-1}/>
      </form>
    </Modal>
  );
}

// ─── Sidebar ──────────────────────────────────────────────────────────
function Sidebar({ collapsed, setCollapsed, currentRoot, navigate, onOpenPalette, onLogout, currentUser, onChangeOwnPassword }) {
  const { ROLES } = window.AxluData;
  const visibleNav = NAV.filter((n) => window.AxluStore.can("nav:" + n.id));
  const userName = currentUser ? currentUser.name : "—";
  const userRole = currentUser ? (ROLES[currentUser.role] && ROLES[currentUser.role].label) || currentUser.role : "—";
  const canManageUsers = window.AxluStore.can("manageUsers");
  return (
    <aside className="surface border-r flex flex-col shrink-0 transition-all" style={{
      borderColor: "var(--border)",
      width: collapsed ? 64 : 240,
      position: "sticky", top: 0, height: "100vh",
    }}>
      {/* Brand */}
      <div className={`flex items-center px-3 h-14 border-b shrink-0 ${collapsed ? "justify-center" : "justify-between"}`} style={{ borderColor: "var(--border)" }}>
        <a href="#/dashboard" className="flex items-center gap-2.5 min-w-0">
          <Logo size={collapsed ? 28 : 32}/>
          {!collapsed && (
            <div className="min-w-0">
              <div className="text-[10.5px] text-subtle leading-none">Middleware ERP</div>
            </div>
          )}
        </a>
        {!collapsed && <IconButton icon="chevronLeft" size="sm" onClick={() => setCollapsed(true)}/>}
      </div>

      {/* Search trigger / cmd K */}
      <div className="px-3 py-3 border-b" style={{ borderColor: "var(--border)" }}>
        {collapsed ? (
          <IconButton icon="search" onClick={onOpenPalette} title="Recherche (⌘K)"/>
        ) : (
          <button onClick={onOpenPalette} className="w-full flex items-center gap-2 h-8 px-2.5 rounded-md sunken text-[12.5px] text-muted hover:text-app transition-colors border" style={{ borderColor: "var(--border)" }}>
            <Icon name="search" size={14}/>
            <span className="flex-1 text-left">Rechercher…</span>
            <kbd>⌘K</kbd>
          </button>
        )}
      </div>

      {/* Nav */}
      <nav className="flex-1 overflow-y-auto py-2">
        {!collapsed && <div className="px-4 py-2 text-[10px] font-semibold uppercase tracking-wider text-subtle">Navigation</div>}
        <div className="px-2 space-y-0.5">
          {visibleNav.map((n) => {
            const active = n.id === currentRoot;
            return (
              <a key={n.id} href={n.href}
                 className={`flex items-center ${collapsed ? "justify-center px-0" : "gap-2.5 px-2.5"} h-8 rounded-md transition-colors text-[13px] ${active ? "accent-bg accent-fg font-medium" : "text-muted hover:text-app hover:bg-[var(--hover)]"}`}
                 title={collapsed ? n.label : undefined}>
                {collapsed
                  ? <span className="text-[16px] leading-none" aria-hidden>{n.emoji}</span>
                  : <>
                      <span className="text-[14px] leading-none w-4 text-center" aria-hidden>{n.emoji}</span>
                      <span>{n.label}</span>
                    </>}
              </a>
            );
          })}
        </div>
      </nav>

      {/* User */}
      <div className="border-t" style={{ borderColor: "var(--border)" }}>
        {collapsed ? (
          <div className="p-2 flex flex-col items-center gap-1.5">
            <button onClick={() => setCollapsed(false)}><Icon name="chevronRight" size={14} className="text-muted"/></button>
            <Avatar name={userName} size={28}/>
            <Dropdown
              trigger={<IconButton icon="more" size="sm"/>}
              align="right" width={220}
              items={[
                { label: "Modifier mon mot de passe", icon: "key", onClick: onChangeOwnPassword },
                ...(canManageUsers ? [{ label: "Utilisateurs", icon: "users", onClick: () => navigate("#/admin") }] : []),
                { label: "Préférences", icon: "settings", onClick: () => { window.dispatchEvent(new CustomEvent("axlu:open-tweaks")); } },
                "sep",
                { label: "Déconnexion", icon: "logout", onClick: onLogout, danger: true },
              ]}/>
          </div>
        ) : (
          <div className="p-3">
            <div className="flex items-center gap-2.5">
              <Avatar name={userName} size={32}/>
              <div className="flex-1 min-w-0">
                <div className="text-[12.5px] font-medium truncate">{userName}</div>
                <div className="text-[11px] text-subtle truncate">{userRole}</div>
                <div className="text-[10.5px] text-subtle truncate mono">v{window.__CACHE_BUST__ || "—"}</div>
              </div>
              <Dropdown
                trigger={<IconButton icon="more" size="sm"/>}
                align="right" width={220}
                items={[
                  { label: "Modifier mon mot de passe", icon: "key", onClick: onChangeOwnPassword },
                  ...(canManageUsers ? [{ label: "Utilisateurs", icon: "users", onClick: () => navigate("#/admin") }] : []),
                  { label: "Préférences", icon: "settings", onClick: () => { window.dispatchEvent(new CustomEvent("axlu:open-tweaks")); } },
                  "sep",
                  { label: "Déconnexion", icon: "logout", onClick: onLogout, danger: true },
                ]}/>
            </div>
          </div>
        )}
      </div>
    </aside>
  );
}

// ─── Command palette ──────────────────────────────────────────────────
function CommandPalette({ open, onClose, navigate }) {
  const { PRODUCTS, SUPPLIERS } = window.AxluData;
  const [q, setQ] = useState("");
  const inputRef = useRef(null);

  useEffect(() => {
    if (open) { setQ(""); setTimeout(() => inputRef.current?.focus(), 50); }
  }, [open]);

  const items = useMemo(() => {
    const out = [];
    NAV.forEach((n) => out.push({ kind: "Navigation", label: n.label, icon: n.icon, href: n.href, hint: "Aller à" }));
    out.push({ kind: "Action", label: "Lancer une synchro globale",  icon: "play",    href: "#/syncs",      hint: "Action" });
    out.push({ kind: "Action", label: "Voir les produits à valider", icon: "warning", href: "#/catalog?status=to_review", hint: "Action" });
    out.push({ kind: "Action", label: "Voir les erreurs Shopify",    icon: "cart",    href: "#/shopify",    hint: "Action" });
    out.push({ kind: "Action", label: "Configurer les règles de prix", icon: "coin",  href: "#/pricing",    hint: "Action" });
    PRODUCTS.slice(0, 30).forEach((p) => out.push({ kind: "Produits", label: p.title, sub: p.sku, icon: "cube", href: `#/products/${p.id}`, hint: "Ouvrir" }));
    SUPPLIERS.forEach((s) => out.push({ kind: "Fournisseurs", label: s.name, icon: "plug", href: `#/suppliers/${s.id}`, hint: "Ouvrir" }));
    if (!q) return out.filter((x) => x.kind === "Navigation" || x.kind === "Action");
    const lower = q.toLowerCase();
    return out.filter((x) => x.label.toLowerCase().includes(lower) || (x.sub || "").toLowerCase().includes(lower)).slice(0, 30);
  }, [q]);

  const grouped = useMemo(() => {
    const g = {};
    items.forEach((it) => { (g[it.kind] = g[it.kind] || []).push(it); });
    return g;
  }, [items]);

  if (!open) return null;
  return (
    <div className="fixed inset-0 z-[100] flex items-start justify-center pt-[12vh] anim-fade" style={{ background: "rgba(0,0,0,.4)" }} onClick={onClose}>
      <div className="surface border rounded-xl w-[600px] max-w-[90vw] anim-scale overflow-hidden" style={{ borderColor: "var(--border)", boxShadow: "var(--shadow-lg)" }} onClick={(e) => e.stopPropagation()}>
        <div className="flex items-center gap-2 px-4 h-12 border-b" style={{ borderColor: "var(--border)" }}>
          <Icon name="search" size={16} className="text-subtle"/>
          <input ref={inputRef} value={q} onChange={(e) => setQ(e.target.value)} placeholder="Rechercher produits, fournisseurs, actions…"
            className="flex-1 bg-transparent outline-none text-[14px] text-app placeholder:text-[var(--fg-subtle)]"/>
          <kbd>esc</kbd>
        </div>
        <div className="overflow-y-auto" style={{ maxHeight: 480 }}>
          {Object.entries(grouped).map(([group, list]) => (
            <div key={group}>
              <div className="px-4 py-1.5 text-[10px] uppercase tracking-wider text-subtle font-semibold sunken">{group}</div>
              {list.map((it, i) => (
                <button key={i} onClick={() => { navigate(it.href); onClose(); }}
                        className="w-full flex items-center gap-3 px-4 py-2 hover:bg-[var(--hover)] text-left">
                  <Icon name={it.icon} size={14} className="text-muted"/>
                  <div className="flex-1 min-w-0">
                    <div className="text-[13px] truncate">{it.label}</div>
                    {it.sub && <div className="text-[11px] mono text-subtle truncate">{it.sub}</div>}
                  </div>
                  <span className="text-[11px] text-subtle">{it.hint}</span>
                </button>
              ))}
            </div>
          ))}
          {items.length === 0 && <EmptyState icon="search" title="Aucun résultat" description="Essayer un autre terme."/>}
        </div>
        <div className="px-4 py-2 sunken text-[11px] text-subtle flex items-center gap-3 border-t" style={{ borderColor: "var(--border)" }}>
          <span className="flex items-center gap-1"><kbd>↑</kbd><kbd>↓</kbd> naviguer</span>
          <span className="flex items-center gap-1"><kbd>↵</kbd> ouvrir</span>
          <span className="flex items-center gap-1"><kbd>esc</kbd> fermer</span>
          <div className="flex-1"/>
          <span>{items.length} résultats</span>
        </div>
      </div>
    </div>
  );
}

// ─── Headless background sync ──────────────────────────────────────────
// Launched by the Windows scheduled task (AXLU.exe --sync) in a hidden
// window: import every supplier feed, flush state to disk, then quit.
async function runHeadlessSync() {
  try {
    const suppliers = (window.AxluData && window.AxluData.SUPPLIERS) || [];
    for (let i = 0; i < suppliers.length; i++) {
      try { await runSupplierFeedsInOrder(suppliers[i], { dueOnly: true }); }
      catch (e) { console.warn("[AXLU] headless sync — supplier failed", e); }
    }
    if (window.AxluStore && typeof window.AxluStore.flush === "function") {
      window.AxluStore.flush();
    }
  } catch (e) {
    console.error("[AXLU] headless sync error", e);
  } finally {
    try { if (window.axlu && window.axlu.headlessSyncDone) window.axlu.headlessSyncDone(); } catch (e) { /* ignore */ }
  }
}

// ─── Mount ─────────────────────────────────────────────────────────────
if (new URLSearchParams(window.location.search).get("headlessSync") === "1") {
  window.__AXLU_HEADLESS__ = true;
  runHeadlessSync();
} else {
  const root = ReactDOM.createRoot(document.getElementById("root"));
  root.render(<><App/><UpdateGate/></>);
}
