/* global React, Icon, Button, Badge, RemoteCard, Pad, BigBtn */
// ============================================================
// Feature "Création de compte Instagram" — panneau gauche + droite + admin
// ============================================================

// ---- Store comptes créés (localStorage) ----
const AccountCreationStore = (function () {
  const KEY = "phonelabs.created_accounts";
  const ls = new Set();
  const emit = () => ls.forEach(f => f());
  const load = () => { try { return JSON.parse(localStorage.getItem(KEY) || "[]"); } catch (e) { return []; } };
  const _pushToBackend = (all) => {
    if (window.Backend && window.Backend.saveIgAccounts) {
      window.Backend.saveIgAccounts(all).catch(() => {});
    }
  };
  return {
    sub(cb) { ls.add(cb); return () => ls.delete(cb); },
    list() { return load(); },
    add(acct) {
      const all = load();
      const operator = (window.__FARM_USER__ && window.__FARM_USER__.name) || "";
      all.unshift({ ...acct, id: String(performance.now()).replace(".", ""), saved_at: new Date().toISOString(), operator, category: acct.category || "Warm Up" });
      const trimmed = all.slice(0, 5000);
      try { localStorage.setItem(KEY, JSON.stringify(trimmed)); } catch (e) {}
      _pushToBackend(trimmed);
      emit();
    },
    update(id, patch) {
      const next = load().map(a => a.id === id ? { ...a, ...patch } : a);
      try { localStorage.setItem(KEY, JSON.stringify(next)); } catch (e) {}
      _pushToBackend(next);
      emit();
    },
    remove(id) {
      const next = load().filter(a => a.id !== id);
      try { localStorage.setItem(KEY, JSON.stringify(next)); } catch (e) {}
      _pushToBackend(next);
      emit();
    },
    count() { return load().length; },
    // Tire les comptes du backend et fusionne (le backend est la source de vérité si non vide)
    async syncFromBackend() {
      if (!window.Backend || !window.Backend.getIgAccounts) return;
      const remote = await window.Backend.getIgAccounts();
      if (!remote || !remote.length) {
        // backend vide → on lui pousse ce qu'on a en local
        const local = load();
        if (local.length) _pushToBackend(local);
        return;
      }
      // Fusionner : union par id, remote + local, dédup par id, tri par saved_at desc
      const local = load();
      const byId = new Map();
      remote.forEach(a => byId.set(a.id, a));
      local.forEach(a => { if (!byId.has(a.id)) byId.set(a.id, a); });
      const merged = [...byId.values()].sort((a, b) => (b.saved_at || "").localeCompare(a.saved_at || ""));
      try { localStorage.setItem(KEY, JSON.stringify(merged.slice(0, 5000))); } catch (e) {}
      emit();
    },
  };
})();
function useAccountStore() {
  const [, f] = React.useReducer(x => x + 1, 0);
  React.useEffect(() => AccountCreationStore.sub(f), []);
  return AccountCreationStore;
}

// ---- Générateurs ----
const _SUFFIXES3 = ["lea", "lou", "lia", "ana", "eva", "mia", "zia", "rue", "eve", "aya", "mla", "ola", "sia", "ema", "ila"];
const _EMOJIS = ["🌸", "🦋", "✨", "🌙", "💫", "🌿", "🎀", "🌺", "💎", "🪷", "🌟", "🍀", "🦢", "🌻", "🐚", "🎐"];
const _SYMBOLS = ["!", "#", "$", "&", "*", "@"];
function _rnd(arr) { return arr[Math.floor(Math.random() * arr.length)]; }
function genNom() {
  const bases = ["Chloé", "Chloe", "Chloë", "Chloea", "Chloée"];
  return _rnd(_EMOJIS) + " " + _rnd(bases);
}
function genUsername() {
  const bases = ["chloe", "chlo", "chloe_", "ch.loe", "chloe."];
  return _rnd(bases) + "." + _rnd(_SUFFIXES3);
}
function genPassword(u) {
  const base = (u || genUsername()).replace(/\.$/, "");
  return base + _rnd(_SYMBOLS) + String(Math.floor(Math.random() * 90 + 10));
}
function genBirthday() {
  const start = new Date(2000, 0, 1).getTime();
  const end = new Date(2007, 11, 31).getTime();
  return new Date(start + Math.random() * (end - start)).toISOString().slice(0, 10);
}

// ---- IP Rotation ----
const IP_URL_FALLBACK = "https://rotateip.ddns.net/backend/api_v1/proxy/change-ip?license=70e5b755-b419-4dc6-9bdb-44cc8d9b5ee5";

async function fetchIpFromUrl(url) {
  // Passe par le backend local Python pour éviter les erreurs CORS
  const res = window.Backend && window.Backend.fetchUrl
    ? await window.Backend.fetchUrl(url)
    : await fetch(url).then(r => r.text()).then(t => { try { return { ok: true, body: JSON.parse(t), raw: t }; } catch(e) { return { ok: true, body: null, raw: t }; } }).catch(e => ({ ok: false, error: e.message, raw: "" }));

  if (!res.ok) return { ok: false, ip: "", raw: (res.error ? res.error + (res.raw ? "\n" + res.raw : "") : res.raw) || "Erreur réseau" };

  const body = res.body;
  const raw = res.raw || "";
  const serverMsg = (body && body.message) ? body.message : raw;
  let ip = "";
  if (body && typeof body === "object") {
    ip = body.ip || body.new_ip || body.proxy || body.address || body.current_ip || body.ipAddress || "";
  }
  if (!ip && /^\d{1,3}(\.\d{1,3}){3}$/.test(raw.trim())) ip = raw.trim();
  // rotateip: "external ip changed from X to Y" → extraire la nouvelle IP
  if (!ip && serverMsg) {
    const m = serverMsg.match(/(?:changed from[\s\S]+?\bto\b\s*)([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3})/i);
    if (m) ip = m[1];
  }
  return { ok: true, ip, raw: serverMsg.slice(0, 200), isChange: serverMsg.toLowerCase().includes("changed") };
}

function IpRotationBar({ onRotated, rotationUrl, proxyName }) {
  const { useState, useEffect, useRef } = React;
  const [ip, setIp] = useState("—");
  const [busy, setBusy] = useState(false);
  const [spinning, setSpinning] = useState(false);
  const [status, setStatus] = useState(null); // null | "ok" | "ratelimit" | "fail"
  const [msg, setMsg] = useState("");
  const url = rotationUrl || IP_URL_FALLBACK;
  const spinRef = useRef(null);

  // Fetch IP actuelle au chargement (sans tourner)
  useEffect(() => {
    (async () => {
      try {
        const res = await (window.Backend && window.Backend.fetchUrl
          ? window.Backend.fetchUrl("https://api.ipify.org?format=json")
          : fetch("https://api.ipify.org?format=json").then(r => r.json()).then(b => ({ ok: true, body: b, raw: "" })));
        if (res.ok && res.body && res.body.ip) setIp(res.body.ip);
      } catch (_) {}
    })();
  }, []);

  const rotate = async () => {
    if (!url) return;
    setBusy(true); setSpinning(true); setStatus(null); setMsg("");
    try {
      const res = await fetchIpFromUrl(url);
      setSpinning(false);
      if (res.ip) {
        setIp(res.ip); setStatus("ok"); setMsg("");
        if (onRotated) onRotated(res.ip);
      } else if (res.raw && res.raw.toLowerCase().includes("wait")) {
        setStatus("ratelimit"); setMsg(res.raw);
      } else {
        setStatus("fail"); setMsg(res.raw || "Pas d'IP dans la réponse");
      }
    } catch (e) { setSpinning(false); setStatus("fail"); setMsg("Erreur : " + e.message); }
    setBusy(false);
  };

  const borderColor = status === "ok" ? "var(--accent-line)" : status === "ratelimit" ? "rgba(251,146,60,.35)" : status === "fail" ? "rgba(255,92,108,.3)" : "var(--border)";
  const ipColor = status === "ok" ? "var(--accent)" : "var(--text)";
  return (
    <div style={{ borderRadius: 11, background: "var(--surface)", border: "1px solid " + borderColor, marginBottom: 12, overflow: "hidden" }}>
      <style>{`@keyframes spin360{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}`}</style>
      <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "10px 13px" }}>
        {React.createElement(Icon.bolt, { size: 15, color: status === "ok" ? "var(--accent)" : "var(--muted)" })}
        <div style={{ display: "flex", flexDirection: "column", flex: 1, minWidth: 0 }}>
          {proxyName && <span style={{ fontSize: 10, fontWeight: 700, color: "var(--accent)", letterSpacing: ".05em", textTransform: "uppercase", marginBottom: 1 }}>{proxyName}</span>}
          <span style={{ fontSize: 11, fontWeight: 700, color: "var(--muted)" }}>IP actuelle</span>
          <span className="mono" style={{ fontSize: 12.5, color: ipColor, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
            {busy && !spinning ? "…" : ip}
          </span>
        </div>
        <button onClick={rotate} disabled={busy} style={{
          display: "flex", alignItems: "center", gap: 6, padding: "6px 12px", borderRadius: 8, fontSize: 12.5, fontWeight: 600,
          cursor: busy ? "not-allowed" : "pointer", border: "none",
          background: status === "ok" ? "var(--accent-soft)" : "var(--accent)",
          color: status === "ok" ? "var(--accent)" : "#06281c", opacity: busy ? .7 : 1 }}>
          <span style={{ display: "inline-block", animation: spinning ? "spin360 .7s linear infinite" : "none" }}>
            {React.createElement(Icon.refresh, { size: 14 })}
          </span>
          {busy ? "Rotation…" : "Rotation IP"}
        </button>
      </div>
      {status === "ok" && <div style={{ padding: "5px 13px 9px", fontSize: 11, color: "var(--accent)", background: "rgba(52,211,153,.04)", borderTop: "1px solid rgba(52,211,153,.12)" }}>✓ IP changée avec succès</div>}
      {status === "ratelimit" && msg && <div style={{ padding: "6px 13px 10px", fontSize: 11, color: "#fb923c", background: "rgba(251,146,60,.06)", borderTop: "1px solid rgba(251,146,60,.2)", wordBreak: "break-all" }}>⏳ {msg}</div>}
      {status === "fail" && msg && <div style={{ padding: "6px 13px 10px", fontSize: 11, color: "var(--danger)", fontFamily: "monospace", background: "rgba(255,92,108,.05)", borderTop: "1px solid rgba(255,92,108,.15)", wordBreak: "break-all" }}>⚠ {msg}</div>}
    </div>
  );
}

// ---- Slide 1 : Demande de numéro (HeroSMS / 5sim) ----
const HSMS_BASE = "https://hero-sms.com/stubs/handler_api.php";
const FSIM_BASE = "https://5sim.net/v1/user";

async function _apiRelay(url, opts) {
  const res = window.Backend && window.Backend.relay
    ? await window.Backend.relay(url, opts)
    : await fetch(url, opts).then(r => r.text()).then(raw => ({ ok: true, body: null, raw })).catch(e => ({ ok: false, error: e.message, raw: "" }));
  return res;
}

async function hsmsOrder(apiKey) {
  const url = `${HSMS_BASE}?api_key=${apiKey}&action=getNumber&service=ig&country=187`;
  const res = await _apiRelay(url);
  const t = res.raw || "";
  if (!t.startsWith("ACCESS_NUMBER:")) throw new Error(t || "Erreur HeroSMS");
  const parts = t.split(":");
  return { orderId: parts[1], phone: parts[2] };
}
async function hsmsCheck(orderId, apiKey) {
  const url = `${HSMS_BASE}?api_key=${apiKey}&action=getStatus&id=${orderId}`;
  const res = await _apiRelay(url);
  const t = res.raw || "";
  if (t.startsWith("STATUS_OK:")) return t.split(":")[1];
  return null;
}
async function fsimOrder(apiKey, country) {
  const c = (country || "usa").toLowerCase();
  const url = `${FSIM_BASE}/buy/activation/${c}/any/instagram`;
  const res = await _apiRelay(url, { method: "GET", headers: { "Authorization": "Bearer " + apiKey } });
  if (!res.ok || !res.body) throw new Error(res.error || res.raw || "Erreur 5sim");
  const b = res.body;
  if (b.message) throw new Error(b.message);
  if (!b.id || !b.phone) throw new Error(JSON.stringify(b).slice(0, 200));
  return { orderId: String(b.id), phone: b.phone.replace(/^\+/, "") };
}
async function fsimCheck(orderId, apiKey) {
  const url = `${FSIM_BASE}/check/${orderId}`;
  const res = await _apiRelay(url, { method: "GET", headers: { "Authorization": "Bearer " + apiKey } });
  if (!res.ok || !res.body) return null;
  const b = res.body;
  if (b.sms && b.sms.length) return b.sms[b.sms.length - 1].code;
  return null;
}

function NumberSlide({ device, onPhone }) {
  const { useState, useEffect, useRef } = React;
  const [provider, setProvider] = useState("herosms");
  const [apiKeys, setApiKeys] = useState({});
  const [state, setState] = useState("idle"); // idle | ordering | waiting | done | err
  const [orderId, setOrderId] = useState(null);
  const [phone, setPhone] = useState("");
  const [smsCode, setSmsCode] = useState("");
  const [manualSms, setManualSms] = useState("");
  const [err, setErr] = useState("");
  const poll = useRef(null);

  useEffect(() => {
    if (window.Backend && window.Backend.getApiKeys) window.Backend.getApiKeys().then(setApiKeys);
    return () => { if (poll.current) clearInterval(poll.current); };
  }, []);

  const order = async () => {
    if (poll.current) clearInterval(poll.current);
    setState("ordering"); setErr(""); setPhone(""); setSmsCode(""); setOrderId(null);
    try {
      const key = provider === "5sim" ? (apiKeys.fsim || "") : (apiKeys.herosms || "");
      if (!key) throw new Error("Clé API manquante — renseigne-la dans Paramètres → Clés API");
      const res = provider === "5sim" ? await fsimOrder(key, apiKeys.fsim_country || "usa") : await hsmsOrder(key);
      setOrderId(res.orderId);
      setPhone(res.phone);
      if (onPhone) onPhone(res.phone);
      setState("waiting");
      poll.current = setInterval(async () => {
        try {
          const code = provider === "5sim" ? await fsimCheck(res.orderId, key) : await hsmsCheck(res.orderId, key);
          if (code) { setSmsCode(code); setState("done"); clearInterval(poll.current); }
        } catch (e) {}
      }, 5000);
    } catch (e) { setErr(e.message || "Erreur"); setState("err"); }
  };

  const submitManual = () => {
    if (!manualSms.trim()) return;
    setSmsCode(manualSms.trim()); setState("done");
    if (poll.current) clearInterval(poll.current);
  };

  const reset = () => {
    if (poll.current) clearInterval(poll.current);
    setState("idle"); setOrderId(null); setPhone(""); setSmsCode(""); setManualSms(""); setErr("");
  };

  const inpSt = { flex: 1, padding: "9px 12px", background: "var(--bg-2,var(--surface-2))", border: "1px solid var(--border)", borderRadius: 9, color: "var(--text)", fontSize: 14, outline: "none", fontFamily: "var(--mono,monospace)", letterSpacing: ".08em" };

  return (
    <RemoteCard title="Demande de numéro" icon="phone">
      <div style={{ display: "flex", gap: 6, marginBottom: 12 }}>
        {[["herosms", "HeroSMS"], ["5sim", "5sim"]].map(([k, l]) => (
          <button key={k} onClick={() => setProvider(k)} style={{
            padding: "5px 11px", borderRadius: 8, fontSize: 11.5, fontWeight: 600, cursor: "pointer", border: "1px solid",
            background: provider === k ? "var(--accent-soft)" : "var(--surface-2)",
            color: provider === k ? "var(--accent)" : "var(--muted)",
            borderColor: provider === k ? "var(--accent-line)" : "var(--border)" }}>
            {l}{k === "herosms" && <span style={{ fontSize: 9.5, marginLeft: 4, opacity: .7 }}>(défaut)</span>}
          </button>
        ))}
      </div>

      {err && <div style={{ fontSize: 12, color: "var(--danger)", marginBottom: 8 }}>{err}</div>}

      {phone && state !== "idle" && (
        <div className="mono" style={{ fontSize: 18, fontWeight: 800, letterSpacing: ".12em", textAlign: "center", padding: "10px 0 8px", color: "var(--text)" }}>
          {phone}
        </div>
      )}

      {(state === "idle" || state === "err") && (
        <button onClick={order} style={{ width: "100%", padding: "11px", borderRadius: 10, fontSize: 13.5, fontWeight: 700, cursor: "pointer", background: "var(--accent)", color: "#06281c", border: "none", display: "flex", alignItems: "center", justifyContent: "center", gap: 8 }}>
          {React.createElement(Icon.phone, { size: 16 })} Demander un numéro
        </button>
      )}
      {state === "ordering" && <div style={{ textAlign: "center", color: "var(--faint)", fontSize: 13, padding: "8px 0" }}>Commande en cours…</div>}
      {state === "waiting" && (
        <div style={{ display: "grid", gap: 8 }}>
          <div style={{ textAlign: "center", color: "var(--busy)", fontSize: 13, display: "flex", alignItems: "center", justifyContent: "center", gap: 8 }}>
            <span style={{ width: 7, height: 7, borderRadius: 99, background: "var(--busy)", animation: "streamPulse 1.2s infinite" }} />
            Attente du SMS…
          </div>
          <div style={{ display: "flex", gap: 7 }}>
            <input value={manualSms} onChange={e => setManualSms(e.target.value)} onKeyDown={e => e.key === "Enter" && submitManual()} placeholder="Code SMS (si auto échoue)…" style={inpSt} />
            <button onClick={submitManual} style={{ padding: "0 12px", borderRadius: 8, background: "var(--surface-2)", border: "1px solid var(--border)", color: "var(--text)", cursor: "pointer", fontWeight: 600 }}>OK</button>
          </div>
          <button onClick={reset} style={{ fontSize: 11, color: "var(--faint)", background: "none", border: "none", cursor: "pointer", textDecoration: "underline" }}>Annuler / Changer de numéro</button>
        </div>
      )}
      {state === "done" && (
        <div style={{ display: "grid", gap: 9 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 14px", borderRadius: 11, background: "var(--accent-soft)", border: "1px solid var(--accent-line)" }}>
            {React.createElement(Icon.check, { size: 20, color: "var(--accent)" })}
            <div>
              <div style={{ fontSize: 10.5, color: "var(--muted)", fontWeight: 600 }}>Code SMS reçu ✓</div>
              <div className="mono" style={{ fontSize: 26, fontWeight: 800, color: "var(--accent)", letterSpacing: ".18em" }}>{smsCode}</div>
            </div>
          </div>
          <button onClick={reset} style={{ fontSize: 12, color: "var(--faint)", background: "none", border: "1px solid var(--border)", borderRadius: 8, padding: "7px", cursor: "pointer" }}>↺ Nouveau numéro</button>
        </div>
      )}
    </RemoteCard>
  );
}

// ---- Slide 2 : Récupération 2FA ----
function TwoFASlide({ device }) {
  const { useState, useEffect, useRef } = React;
  const [totpKey, setTotpKey] = useState("");
  const [code, setCode] = useState("");
  const [timer, setTimer] = useState(30);
  const [scanning, setScanning] = useState(false);
  const [scanErr, setScanErr] = useState("");
  const [copiedKey, setCopiedKey] = useState(false);
  const [copiedCode, setCopiedCode] = useState(false);
  const tickRef = useRef(null);

  const copyText = (text, setCopied) => {
    navigator.clipboard.writeText(text).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1500); }).catch(() => {});
  };

  const fetchCode = async (key) => {
    const clean = (key || totpKey).replace(/\s+/g, "");
    if (!clean) return;
    // 1. pyotp via backend (le plus fiable)
    if (window.Backend && window.Backend.totp) {
      const res = await window.Backend.totp(clean);
      if (res.ok && res.token) { setCode(res.token); setTimer(res.remaining || 30); return; }
    }
    // 2. twofa.co API en fallback
    try {
      const res = await _apiRelay(`https://2fa.co/api/totp/${clean}`);
      if (res.ok && res.body) {
        const tok = res.body.token || res.body.totp || res.body.code || res.body.otp || "";
        if (tok) { setCode(String(tok)); return; }
      }
    } catch (_) {}
    // 3. 2fa.live en dernier recours
    try {
      const res = await _apiRelay(`https://2fa.live/tok/${clean}`, { headers: { "User-Agent": "Mozilla/5.0" } });
      if (res.ok && res.body && res.body.token) { setCode(res.body.token); return; }
    } catch (_) {}
  };

  useEffect(() => {
    if (!totpKey.trim()) { setCode(""); if (tickRef.current) clearInterval(tickRef.current); return; }
    fetchCode(totpKey);
    tickRef.current = setInterval(() => {
      const secs = Math.floor(Date.now() / 1000);
      const rem = 30 - (secs % 30);
      setTimer(rem);
      if (rem >= 29) fetchCode(totpKey);
    }, 1000);
    return () => clearInterval(tickRef.current);
  }, [totpKey]);

  const scan = async () => {
    if (!device || !device.udid) { setScanErr("Device non connecté"); return; }
    setScanning(true); setScanErr("");
    try {
      const keys = window.Backend && window.Backend.getApiKeys ? await window.Backend.getApiKeys() : {};
      const base = "http://127.0.0.1:8787";
      const r = await fetch(`${base}/api/devices/${encodeURIComponent(device.udid)}/gemini-totp`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ gemini_key: keys.gemini || "" })
      });
      if (!r.ok) throw new Error("HTTP " + r.status);
      const j = await r.json();
      if (j.totp_key) { setTotpKey(j.totp_key); setScanErr(""); }
      else setScanErr(j.error || "Clé TOTP non trouvée dans la capture");
    } catch (e) { setScanErr("Erreur : " + e.message); }
    setScanning(false);
  };

  const timerColor = timer <= 5 ? "var(--danger)" : timer <= 10 ? "var(--busy)" : "var(--accent)";
  const inpSt = { flex: 1, padding: "9px 12px", background: "var(--bg-2,var(--surface-2))", border: "1px solid var(--border)", borderRadius: 9, color: "var(--text)", fontSize: 12, outline: "none", fontFamily: "var(--mono,monospace)", letterSpacing: ".07em" };
  const copyBtn = (copied, onClick) => (
    <button onClick={onClick} title="Copier" style={{ padding: "8px 11px", borderRadius: 8, background: copied ? "var(--accent-soft)" : "var(--surface-2)", border: "1px solid " + (copied ? "var(--accent-line)" : "var(--border)"), color: copied ? "var(--accent)" : "var(--muted)", cursor: "pointer", fontSize: 13, flex: "none" }}>
      {copied ? "✓" : "⎘"}
    </button>
  );

  return (
    <RemoteCard title="Récupération 2FA (TOTP)" icon="shield">
      <button onClick={scan} disabled={scanning} style={{ width: "100%", padding: "10px", borderRadius: 9, fontSize: 13, fontWeight: 700, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: 8, border: "none", background: "var(--accent)", color: "#06281c", marginBottom: 12, opacity: scanning ? .6 : 1 }}>
        {React.createElement(Icon.play, { size: 15 })} {scanning ? "Analyse de l'écran…" : "Scanner la clé TOTP (Gemini)"}
      </button>
      {scanErr && <div style={{ fontSize: 12, color: "var(--danger)", marginBottom: 8 }}>{scanErr}</div>}

      <div style={{ marginBottom: 12 }}>
        <label style={{ fontSize: 10.5, color: "var(--muted)", fontWeight: 600, display: "block", marginBottom: 4 }}>Clé TOTP Base32 (auto ou manuelle)</label>
        <div style={{ display: "flex", gap: 6 }}>
          <input value={totpKey} onChange={e => setTotpKey(e.target.value.toUpperCase())} placeholder="XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX" style={inpSt} />
          {totpKey.trim() && copyBtn(copiedKey, () => copyText(totpKey.trim(), setCopiedKey))}
        </div>
      </div>

      {totpKey.trim() && (
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "14px 16px", borderRadius: 12, background: "var(--surface-2)", border: "1px solid var(--border)" }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 10.5, color: "var(--muted)", fontWeight: 600, marginBottom: 4 }}>Code 2FA actuel</div>
            <div className="mono" style={{ fontSize: 30, fontWeight: 800, letterSpacing: ".22em", color: timerColor, lineHeight: 1 }}>{code || "——"}</div>
          </div>
          {code && copyBtn(copiedCode, () => copyText(code, setCopiedCode))}
          <div style={{ textAlign: "center", flex: "none" }}>
            <svg width="40" height="40" viewBox="0 0 46 46">
              <circle cx="23" cy="23" r="20" fill="none" stroke="var(--border)" strokeWidth="3" />
              <circle cx="23" cy="23" r="20" fill="none" stroke={timerColor} strokeWidth="3"
                strokeDasharray={`${(timer / 30) * 125.66} 125.66`} strokeLinecap="round" transform="rotate(-90 23 23)"
                style={{ transition: "stroke-dasharray .9s linear, stroke .3s" }} />
            </svg>
            <div className="mono" style={{ fontSize: 12, fontWeight: 700, color: timerColor, marginTop: 2 }}>{timer}s</div>
          </div>
        </div>
      )}
    </RemoteCard>
  );
}

// ---- Panneau gauche mode création ----
function CreationLeftPanel({ device, user }) {
  const { useState, useEffect } = React;
  const store = useAccountStore();
  const udid = device && device.udid ? device.udid : "default";
  const lsKey = "creation_panel_" + udid;

  // Charge depuis localStorage au montage
  const loadState = () => {
    try { return JSON.parse(localStorage.getItem(lsKey) || "{}"); } catch (_) { return {}; }
  };
  const s0 = loadState();
  const [nom, setNom] = useState(s0.nom || "");
  const [username, setUsername] = useState(s0.username || "");
  const [password, setPassword] = useState(s0.password || "");
  const [totpKey, setTotpKey] = useState(s0.totpKey || "");
  const [phone, setPhone] = useState(s0.phone || "");
  const [birthday, setBirthday] = useState(s0.birthday || "");
  const [busy, setBusy] = useState(false);
  const [saved, setSaved] = useState(false);
  const [blocked, setBlocked] = useState(false);
  const [confirmBlock, setConfirmBlock] = useState(false);
  // Étapes SOP : par défaut le tableau hardcodé, remplacé par la version D1 si elle existe
  const [sopSteps, setSopSteps] = useState(CREATION_STEPS);
  const [steps, setSteps] = useState(s0.steps || CREATION_STEPS.map(() => false));
  const [stepsOpen, setStepsOpen] = useState(true);
  const done = steps.filter(Boolean).length;

  // Charge les étapes depuis la SOP D1 (override de la builtin)
  useEffect(() => {
    if (!window.Backend || !window.Backend.sops) return;
    window.Backend.sops().then(all => {
      if (!all) return;
      const found = all.find(s => s.id === "__builtin_creation_compte" || s.phase === "creation_compte");
      if (found && Array.isArray(found.steps) && found.steps.length > 0) {
        setSopSteps(found.steps);
        // adapter le tableau de cases cochées si la longueur a changé
        setSteps(prev => {
          if (prev.length === found.steps.length) return prev;
          const next = found.steps.map((_, i) => prev[i] || false);
          return next;
        });
      }
    }).catch(() => {});
  }, []);

  // Persiste à chaque changement
  useEffect(() => {
    try { localStorage.setItem(lsKey, JSON.stringify({ nom, username, password, totpKey, phone, birthday, steps })); } catch (_) {}
  }, [nom, username, password, totpKey, phone, birthday, steps]);

  const canEdit = true; // opérateur en mode création peut toujours éditer
  const filled = nom.trim() && username.trim() && password.trim();

  const validate = async () => {
    if (!filled) return;
    setBusy(true);
    try {
      store.add({ nom, username, password, totp_key: totpKey, phone, birthday, device_udid: device.udid, device_tag: device.tag });
      if (window.Backend && window.Backend.log) window.Backend.log({ action: "compte_créé", detail: `@${username} · ${phone || ""}`, udid: device.udid, label: device.tag || device.label || "" });
      if (window.Backend && window.Backend.patchMeta) {
        await window.Backend.patchMeta(device.udid, {
          accounts: JSON.stringify([{ name: username, pass: password, created: new Date().toISOString().slice(0, 10), status: "cree" }])
        });
      }
      setSaved(true); setTimeout(() => setSaved(false), 3500);
    } catch (e) {}
    setBusy(false);
  };

  const restart = () => {
    setNom(""); setUsername(""); setPassword(""); setTotpKey(""); setPhone(""); setBirthday("");
    setSteps(sopSteps.map(() => false));
    setSaved(false); setBlocked(false); setConfirmBlock(false);
    try { localStorage.removeItem(lsKey); } catch (_) {}
  };

  const inp = { width: "100%", background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 8, padding: "7px 10px", color: "var(--text)", fontSize: 13, boxSizing: "border-box", outline: "none" };
  const lbl = { fontSize: 10.5, color: "var(--muted)", fontWeight: 600, marginBottom: 4, display: "block" };
  const genBtn = (onClick) => (
    <button onClick={onClick} title="Générer" style={{ background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 8, padding: "0 9px", color: "var(--muted)", cursor: "pointer", fontSize: 15, flex: "none" }}>🎲</button>
  );
  const valBtn = (active) => (
    <button title="Valider" style={{ background: active ? "var(--accent-soft)" : "var(--surface-2)", border: "1px solid " + (active ? "var(--accent-line)" : "var(--border)"), borderRadius: 8, padding: "0 10px", color: active ? "var(--accent)" : "var(--faint)", cursor: "pointer", flex: "none", fontWeight: 700 }}>✓</button>
  );

  if (blocked) return (
    <div style={{ background: "rgba(255,92,108,.07)", border: "1px solid rgba(255,92,108,.3)", borderRadius: 14, padding: "30px 20px", textAlign: "center", marginBottom: 18 }}>
      {React.createElement(Icon.x, { size: 32, color: "var(--danger)" })}
      <div style={{ fontWeight: 700, fontSize: 15, marginTop: 10, color: "var(--danger)" }}>Création bloquée</div>
      <div style={{ fontSize: 12, color: "var(--faint)", marginTop: 6, marginBottom: 20 }}>Ce téléphone est temporairement bloqué.</div>
      <button onClick={restart} style={{ display: "inline-flex", alignItems: "center", gap: 7, padding: "10px 18px", borderRadius: 10, background: "var(--surface-2)", border: "1px solid var(--border)", color: "var(--text)", fontWeight: 600, cursor: "pointer" }}>
        {React.createElement(Icon.refresh, { size: 15 })} Restart
      </button>
    </div>
  );

  return (
    <div style={{ display: "grid", gap: 11, marginBottom: 18 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, margin: "2px 2px 0", color: "var(--muted)" }}>
        {React.createElement(Icon.apps, { size: 16 })}
        <span style={{ fontSize: 12, fontWeight: 700, letterSpacing: ".06em", textTransform: "uppercase" }}>Création de compte</span>
        {saved && <span style={{ fontSize: 11.5, color: "var(--accent)", marginLeft: "auto", fontWeight: 700 }}>✓ Enregistré</span>}
      </div>

      <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 12, padding: 14, display: "grid", gap: 11 }}>

        {/* Nom */}
        <div>
          <label style={lbl}>Nom complet <span style={{ fontWeight: 400, color: "var(--faint)" }}>· avec emoji</span></label>
          <div style={{ display: "flex", gap: 6 }}>
            <input value={nom} onChange={e => setNom(e.target.value)} placeholder="✨ Chloé…" style={{ ...inp, flex: 1 }} />
            {genBtn(() => setNom(genNom()))}
            {valBtn(!!nom.trim())}
          </div>
        </div>

        {/* Username */}
        <div>
          <label style={lbl}>Username</label>
          <div style={{ display: "flex", gap: 6 }}>
            <input value={username} onChange={e => setUsername(e.target.value)} placeholder="chloe.lea…" style={{ ...inp, flex: 1, fontFamily: "var(--mono,monospace)" }} />
            {genBtn(() => { const u = genUsername(); setUsername(u); if (!password) setPassword(genPassword(u)); })}
            {valBtn(!!username.trim())}
          </div>
        </div>

        {/* Password */}
        <div>
          <label style={lbl}>Mot de passe</label>
          <div style={{ display: "flex", gap: 6 }}>
            <input value={password} onChange={e => setPassword(e.target.value)} placeholder="chloe.lea!25…" style={{ ...inp, flex: 1, fontFamily: "var(--mono,monospace)" }} />
            {genBtn(() => setPassword(genPassword(username || genUsername())))}
            {valBtn(!!password.trim())}
          </div>
        </div>

        {/* 2FA */}
        <div>
          <label style={lbl}>Clé 2FA TOTP <span style={{ fontWeight: 400, color: "var(--faint)" }}>· copier depuis le slide 2FA</span></label>
          <div style={{ display: "flex", gap: 6 }}>
            <input value={totpKey} onChange={e => setTotpKey(e.target.value.toUpperCase())} placeholder="XXXX XXXX XXXX…" style={{ ...inp, flex: 1, fontFamily: "var(--mono,monospace)", fontSize: 11.5 }} />
            {valBtn(!!totpKey.trim())}
          </div>
        </div>

        {/* Date de naissance */}
        <div>
          <label style={lbl}>Date de naissance <span style={{ fontWeight: 400, color: "var(--faint)" }}>· 2000 – 2007</span></label>
          <div style={{ display: "flex", gap: 6 }}>
            <input type="date" value={birthday} onChange={e => setBirthday(e.target.value)} min="2000-01-01" max="2007-12-31" style={{ ...inp, flex: 1 }} />
            {genBtn(() => setBirthday(genBirthday()))}
            {valBtn(!!birthday)}
          </div>
        </div>

      </div>

      {/* Valider le compte */}
      <button onClick={validate} disabled={busy || !filled} style={{
        padding: "13px", borderRadius: 12, fontSize: 14, fontWeight: 700, cursor: filled ? "pointer" : "default",
        background: saved ? "var(--accent)" : filled ? "var(--accent)" : "var(--surface-2)",
        color: saved ? "#06281c" : filled ? "#06281c" : "var(--faint)",
        border: "1px solid " + (filled ? "var(--accent-line)" : "var(--border)"),
        transition: "all .15s", display: "flex", alignItems: "center", justifyContent: "center", gap: 8
      }}>
        {React.createElement(Icon[saved ? "check" : "apps"], { size: 16 })}
        {busy ? "Enregistrement…" : saved ? "✓ Compte validé" : "Valider le compte"}
      </button>

      {/* Blocage / Restart */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
        {confirmBlock ? (
          <>
            <button onClick={() => setBlocked(true)} style={{ padding: "10px", borderRadius: 10, fontSize: 12.5, fontWeight: 700, cursor: "pointer", background: "rgba(255,92,108,.14)", color: "var(--danger)", border: "1px solid rgba(255,92,108,.35)" }}>
              ⛔ Confirmer blocage
            </button>
            <button onClick={() => setConfirmBlock(false)} style={{ padding: "10px", borderRadius: 10, fontSize: 12.5, fontWeight: 600, cursor: "pointer", background: "var(--surface-2)", color: "var(--muted)", border: "1px solid var(--border)" }}>
              Annuler
            </button>
          </>
        ) : (
          <>
            <button onClick={() => setConfirmBlock(true)} style={{ padding: "10px", borderRadius: 10, fontSize: 12.5, fontWeight: 600, cursor: "pointer", background: "var(--surface-2)", color: "var(--danger)", border: "1px solid rgba(255,92,108,.3)" }}>
              ⛔ Bloquer la création
            </button>
            <button onClick={restart} style={{ padding: "10px", borderRadius: 10, fontSize: 12.5, fontWeight: 600, cursor: "pointer", background: "var(--surface-2)", color: "var(--muted)", border: "1px solid var(--border)", display: "flex", alignItems: "center", justifyContent: "center", gap: 6 }}>
              {React.createElement(Icon.refresh, { size: 14 })} Restart
            </button>
          </>
        )}
      </div>

      {/* Étapes de création */}
      <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 12, padding: 14 }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: stepsOpen ? 10 : 0, cursor: "pointer" }} onClick={() => setStepsOpen(o => !o)}>
          <div style={{ display: "flex", alignItems: "center", gap: 8, color: "var(--muted)" }}>
            {React.createElement(Icon.clipboard, { size: 15 })}
            <span style={{ fontSize: 12, fontWeight: 700, letterSpacing: ".06em", textTransform: "uppercase" }}>Étapes</span>
            <span style={{ fontSize: 11.5, color: done === sopSteps.length ? "var(--accent)" : "var(--faint)", fontWeight: 600 }}>{done}/{sopSteps.length}</span>
            {done === sopSteps.length && <span style={{ fontSize: 11, color: "var(--accent)", fontWeight: 700 }}>✓ Terminé</span>}
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <button onClick={e => { e.stopPropagation(); setSteps(sopSteps.map(() => false)); }} style={{ fontSize: 11, color: "var(--faint)", background: "none", border: "none", cursor: "pointer" }}>Réinit.</button>
            <span style={{ fontSize: 16, color: "var(--faint)", lineHeight: 1, transform: stepsOpen ? "rotate(0deg)" : "rotate(-90deg)", display: "inline-block", transition: "transform .15s" }}>▾</span>
          </div>
        </div>
        {stepsOpen && <div style={{ display: "grid", gap: 4, maxHeight: 420, overflowY: "auto" }}>
          {sopSteps.map((s, i) => (
            <label key={i} onClick={() => setSteps(prev => prev.map((v, j) => j === i ? !v : v))}
              style={{ display: "flex", alignItems: "center", gap: 9, padding: "7px 9px", borderRadius: 8, cursor: "pointer",
                background: steps[i] ? "var(--accent-soft)" : "var(--surface-2)",
                border: "1px solid " + (steps[i] ? "var(--accent-line)" : "var(--border)") }}>
              <span style={{ width: 16, height: 16, borderRadius: 4, flex: "none", display: "grid", placeItems: "center",
                background: steps[i] ? "var(--accent)" : "transparent",
                border: "1.5px solid " + (steps[i] ? "var(--accent)" : "var(--border-2,var(--border))"),
                color: "#06281c" }}>
                {steps[i] && React.createElement(Icon.check, { size: 10, sw: 3 })}
              </span>
              <span style={{ fontSize: 11.5, fontWeight: 500, textDecoration: steps[i] ? "line-through" : "none", color: steps[i] ? "var(--muted)" : "var(--text)" }}>
                <span className="mono" style={{ fontSize: 10, color: "var(--faint)", marginRight: 4 }}>{i + 1}.</span>{s}
              </span>
            </label>
          ))}
        </div>}
      </div>
    </div>
  );
}

// ---- Télécommande mode création (droite) ----
const CREATION_STEPS = [
  "Rotation d'IP",
  "Désinstaller Instagram (long press)",
  "Réinstaller Instagram (App Store)",
  "Ouvrir Instagram → Créer un compte",
  "Saisir le numéro de téléphone",
  "Choisir la date de naissance (2000–2007)",
  "Saisir le nom complet",
  "Choisir le username",
  "Saisir le mot de passe",
  "Entrer le code SMS",
  "Accepter les cookies",
  "Ignorer les contacts",
  "Ignorer la photo de profil",
  "Passer les suggestions (×3)",
  "Autoriser les notifications",
  "Fermer Instagram",
  "Activer la 2FA (Accounts Center)",
];

function CreationRemote({ act, busyBtn, dead, device }) {
  const { useState, useEffect } = React;
  const [text, setText] = useState("");
  const [proxies, setProxies] = useState([]);
  const [infoOpen, setInfoOpen] = useState(false);
  const send = () => { if (!text.trim()) return; act("Saisie texte", "kb", text); setText(""); };

  useEffect(() => {
    if (window.Backend && window.Backend.proxies) window.Backend.proxies().then(setProxies);
  }, []);

  const proxy = proxies.find(p => p.id === device.proxy) || null;

  return (
    <div style={{ display: "grid", gap: 10 }}>
      {/* Badge proxy */}
      <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "9px 13px", borderRadius: 10,
        background: proxy ? "rgba(52,211,153,.07)" : "var(--surface)",
        border: "1px solid " + (proxy ? "rgba(52,211,153,.25)" : "var(--border)") }}>
        <span style={{ fontSize: 18 }}>🔌</span>
        <div style={{ flex: 1 }}>
          <span style={{ fontSize: 12, fontWeight: 700, color: proxy ? "var(--accent)" : "var(--faint)" }}>
            {proxy ? proxy.name : "Aucun proxy assigné"}
          </span>
        </div>
        {proxy && proxy.host && (
          <div style={{ position: "relative" }}>
            <button onClick={() => setInfoOpen(o => !o)} style={{ width: 22, height: 22, borderRadius: "50%", background: "rgba(251,146,60,.15)", border: "1.5px solid rgba(251,146,60,.5)", color: "#fb923c", fontWeight: 800, fontSize: 12, cursor: "pointer", display: "grid", placeItems: "center", lineHeight: 1 }}>i</button>
            {infoOpen && (
              <div onClick={() => setInfoOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 999 }}>
                <div onClick={e => e.stopPropagation()} style={{ position: "absolute", right: 0, top: 28, zIndex: 1000, background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 12, padding: 16, width: 280, boxShadow: "0 8px 32px rgba(0,0,0,.35)" }}>
                  <div style={{ fontSize: 12, fontWeight: 700, color: "var(--text)", marginBottom: 10 }}>Infos proxy — {proxy.name}</div>
                  <div style={{ display: "grid", gap: 6, marginBottom: 14 }}>
                    <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                      <span style={{ fontSize: 11, color: "var(--faint)", width: 50, flex: "none" }}>Host</span>
                      <span className="mono" style={{ fontSize: 12, color: "var(--text)", background: "var(--surface-2)", padding: "3px 8px", borderRadius: 6, flex: 1, wordBreak: "break-all" }}>{proxy.host}{proxy.port ? ":" + proxy.port : ""}</span>
                    </div>
                  </div>
                  <div style={{ fontSize: 11, color: "var(--muted)", lineHeight: 1.6, background: "var(--surface-2)", borderRadius: 8, padding: "10px 12px" }}>
                    <span style={{ fontWeight: 700, color: "var(--text)" }}>Vérifier sur ShadowRocket :</span><br />
                    1. Ouvre ShadowRocket sur l'iPhone<br />
                    2. Vérifie que le proxy actif correspond à :<br />
                    <span className="mono" style={{ color: "var(--accent)", fontSize: 11.5 }}>{proxy.host}</span><br />
                    3. Si c'est le bon host → l'iPhone est bien sur ce proxy ✓
                  </div>
                </div>
              </div>
            )}
          </div>
        )}
      </div>

      {/* IP Rotation — utilise l'URL du proxy assigné */}
      <IpRotationBar rotationUrl={proxy ? proxy.url : null} proxyName={proxy ? proxy.name : null} />

      {/* Contrôles iPhone */}
      <RemoteCard title="Contrôles iPhone" icon="apps">
        {/* D-pad gauche + Home droite */}
        <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 10 }}>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(3,44px)", gridTemplateRows: "repeat(3,44px)", gap: 4 }}>
            <span /><Pad id="down" icon="down" label="Bas" act={act} busyBtn={busyBtn} dead={dead} cross /><span />
            <Pad id="right" icon="right" label="Droite" act={act} busyBtn={busyBtn} dead={dead} cross />
            <Pad id="refresh" icon="refresh" act={act} busyBtn={busyBtn} dead={false} cross center />
            <Pad id="left" icon="left" label="Gauche" act={act} busyBtn={busyBtn} dead={dead} cross />
            <span /><Pad id="up" icon="up" label="Haut" act={act} busyBtn={busyBtn} dead={dead} cross /><span />
          </div>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "center", flex: 1 }}>
            <BigBtn id="home" icon="home" label="Home" act={act} busyBtn={busyBtn} dead={dead} />
          </div>
        </div>
        {/* Saisie texte */}
        <div style={{ display: "flex", gap: 8 }}>
          <input value={text} onChange={e => setText(e.target.value)} onKeyDown={e => e.key === "Enter" && send()}
            disabled={dead} placeholder="Saisir du texte…"
            style={{ flex: 1, padding: "9px 10px", background: "var(--bg-2,var(--surface-2))", border: "1px solid var(--border)", borderRadius: 8, color: "var(--text)", fontSize: 13, outline: "none", opacity: dead ? .45 : 1 }} />
          <button onClick={send} disabled={dead || !text.trim()} style={{ padding: "0 13px", borderRadius: 8, background: "var(--accent)", color: "#06281c", border: "none", fontWeight: 700, cursor: "pointer", opacity: dead ? .45 : 1 }}>
            {React.createElement(Icon.send, { size: 16 })}
          </button>
        </div>
      </RemoteCard>

      {/* Slide 1 : Numéro */}
      <NumberSlide device={device} />

      {/* Slide 2 : 2FA */}
      <TwoFASlide device={device} />
    </div>
  );
}

// ---- Page admin : Stockage de comptes ----
const CAT_KEY = "phonelabs.categories";
function loadCategories() {
  try {
    const raw = JSON.parse(localStorage.getItem(CAT_KEY) || '[{"label":"Warm Up","emoji":"🔥"}]');
    return raw.map(c => typeof c === "string" ? { label: c, emoji: "" } : c);
  } catch (_) { return [{ label: "Warm Up", emoji: "🔥" }]; }
}
function saveCategories(cats) { try { localStorage.setItem(CAT_KEY, JSON.stringify(cats)); } catch (_) {} }

const CAT_EMOJIS = ["1️⃣","2️⃣","3️⃣","4️⃣","5️⃣","🔥","⭐","💎","🚀","✅","🌱","🎯","💪","🕐","📅","🗂️","🏆","⚡","🌊","🎀","🍀","💫","🔑","🛡️","🎭","🧪","📊","🔵","🟢","🟡","🟠","🔴","🟣","⚫","⬜"];

function EmojiPicker({ current, onSelect, onClose }) {
  return (
    <div style={{ position: "absolute", zIndex: 200, top: "calc(100% + 6px)", left: 0, background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 10, padding: 8, display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 2, boxShadow: "0 8px 24px rgba(0,0,0,.25)", width: 168 }}
      onMouseDown={e => e.preventDefault()}>
      <button onClick={() => onSelect("")} title="Aucun emoji"
        style={{ fontSize: 14, padding: "4px", borderRadius: 6, border: "1px solid " + (!current ? "var(--accent)" : "transparent"), background: !current ? "var(--accent-soft)" : "none", cursor: "pointer", color: "var(--faint)" }}>✕</button>
      {CAT_EMOJIS.map(e => (
        <button key={e} onClick={() => onSelect(e)}
          style={{ fontSize: 16, padding: "3px", borderRadius: 6, border: "1px solid " + (current === e ? "var(--accent)" : "transparent"), background: current === e ? "var(--accent-soft)" : "none", cursor: "pointer" }}>{e}</button>
      ))}
    </div>
  );
}

function _pctDiff(curr, prev) {
  if (prev === 0 && curr === 0) return null;
  if (prev === 0) return "+100%";
  const p = Math.round(((curr - prev) / prev) * 100);
  return (p >= 0 ? "+" : "") + p + "%";
}
function _pctColor(curr, prev) {
  if (prev === 0 && curr === 0) return "var(--faint)";
  return curr >= prev ? "#4ade80" : "#f87171";
}
function _countInRange(accounts, fromMs, toMs) {
  return accounts.filter(a => {
    const t = a.saved_at ? new Date(a.saved_at).getTime() : 0;
    return t >= fromMs && t < toMs;
  }).length;
}

function CreationsChart({ accounts, days, customStart, hourMode }) {
  const { useState: useS } = React;
  const [hovered, setHovered] = useS(null);
  const W = 680, BAR_AREA_H = 110, LABEL_H = 20;
  const H = BAR_AREA_H + LABEL_H;
  const PAD_L = 28, PAD_R = 12, PAD_TOP = 16;
  const now = new Date();
  const data = [];

  if (hourMode) {
    // 24 barres = 24 dernières heures par tranches d'1h
    for (let i = 23; i >= 0; i--) {
      const slotEnd = new Date(now - i * 3600000);
      const slotStart = new Date(slotEnd - 3600000);
      const h = slotStart.getHours();
      data.push({
        key: slotStart.toISOString(),
        label: String(h).padStart(2, "0") + "h",
        count: _countInRange(accounts, slotStart.getTime(), slotEnd.getTime()),
        isWeekend: false,
        tooltip: String(h).padStart(2, "0") + "h00–" + String((h + 1) % 24).padStart(2, "0") + "h00",
      });
    }
  } else {
    const startDate = customStart ? new Date(customStart) : new Date(now - (days - 1) * 86400000);
    startDate.setHours(0, 0, 0, 0);
    for (let i = 0; i < days; i++) {
      const d = new Date(startDate.getTime() + i * 86400000);
      const key = d.toISOString().slice(0, 10);
      const dayOfWeek = d.getDay();
      data.push({ key, label: key.slice(5), count: accounts.filter(a => (a.saved_at || "").slice(0, 10) === key).length, isWeekend: dayOfWeek === 0 || dayOfWeek === 6, tooltip: key });
    }
  }

  const maxC = Math.max(...data.map(d => d.count), 1);
  const total = data.reduce((s, d) => s + d.count, 0);
  const barCount = data.length;
  const plotW = W - PAD_L - PAD_R;
  const step = plotW / barCount;
  const bw = Math.min(step * 0.65, 32);
  const barH = (c) => Math.max(c > 0 ? 6 : 0, Math.round((c / maxC) * (BAR_AREA_H - PAD_TOP - 4)));
  const uniqueGrid = [...new Set([0, 0.5, 1].map(p => Math.round(p * maxC)))];
  const periodLabel = hourMode ? "24 dernières heures" : (days === 1 ? "aujourd'hui" : `${days} jours`);

  return (
    <div style={{ position: "relative" }}>
      <div style={{ display: "flex", alignItems: "baseline", gap: 16, marginBottom: 8 }}>
        <span style={{ fontSize: 22, fontWeight: 800, color: "var(--text)", letterSpacing: "-.02em" }}>{total}</span>
        <span style={{ fontSize: 12, color: "var(--faint)" }}>compte{total !== 1 ? "s" : ""} — {periodLabel}</span>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: H, overflow: "visible" }}>
        <defs>
          <linearGradient id="barGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#4ade80" stopOpacity="1" />
            <stop offset="100%" stopColor="#16a34a" stopOpacity="0.85" />
          </linearGradient>
          <linearGradient id="barGradHov" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#86efac" stopOpacity="1" />
            <stop offset="100%" stopColor="#4ade80" stopOpacity="1" />
          </linearGradient>
          <linearGradient id="barEmpty" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#888" stopOpacity="0.12" />
            <stop offset="100%" stopColor="#888" stopOpacity="0.06" />
          </linearGradient>
        </defs>
        {uniqueGrid.map(v => {
          const gy = BAR_AREA_H - barH(v) - 2;
          return (
            <g key={v}>
              <line x1={PAD_L} y1={gy} x2={W - PAD_R} y2={gy} stroke="var(--border)" strokeWidth={0.5} strokeDasharray="3,3" />
              <text x={PAD_L - 4} y={gy + 3} textAnchor="end" fontSize={8.5} fill="var(--faint)">{v}</text>
            </g>
          );
        })}
        <line x1={PAD_L} y1={BAR_AREA_H} x2={W - PAD_R} y2={BAR_AREA_H} stroke="var(--border)" strokeWidth={1} />
        {data.map((d, i) => {
          const bh = barH(d.count);
          const cx = PAD_L + i * step + step / 2;
          const x = cx - bw / 2;
          const y = BAR_AREA_H - bh;
          const isHov = hovered === i;
          const showLabel = barCount <= 14 || i % Math.ceil(barCount / 12) === 0;
          return (
            <g key={d.key + i} onMouseEnter={() => setHovered(i)} onMouseLeave={() => setHovered(null)} style={{ cursor: "default" }}>
              {isHov && <rect x={cx - step / 2} y={PAD_TOP} width={step} height={BAR_AREA_H - PAD_TOP} rx={4} fill="var(--accent)" opacity={0.06} />}
              <rect x={x} y={d.count > 0 ? y : BAR_AREA_H - 2} width={bw} height={d.count > 0 ? bh : 2} rx={Math.min(4, bw / 2)}
                fill={d.count > 0 ? (isHov ? "url(#barGradHov)" : "url(#barGrad)") : "url(#barEmpty)"} />
              {d.count > 0 && bh > 8 && <rect x={x} y={y} width={bw} height={Math.min(8, bh)} rx={Math.min(4, bw / 2)} fill={isHov ? "url(#barGradHov)" : "url(#barGrad)"} />}
              {d.count > 0 && (isHov || barCount <= 10) && (
                <text x={cx} y={y - 5} textAnchor="middle" fontSize={9.5} fill={isHov ? "#4ade80" : "var(--accent)"} fontWeight="700">{d.count}</text>
              )}
              {showLabel && (
                <text x={cx} y={BAR_AREA_H + 14} textAnchor="middle" fontSize={9} fill={d.isWeekend ? "var(--muted)" : "var(--faint)"} fontWeight={d.isWeekend ? "600" : "400"}>{d.label}</text>
              )}
              {isHov && (
                <g transform={`translate(${Math.min(Math.max(cx, 40), W - 80)}, ${Math.max(y - 36, 2)})`}>
                  <rect x={-1} y={-1} width={90} height={26} rx={6} fill="var(--surface-2)" stroke="var(--border)" strokeWidth={1} />
                  <text x={44} y={9} textAnchor="middle" fontSize={9} fill="var(--faint)">{d.tooltip}</text>
                  <text x={44} y={20} textAnchor="middle" fontSize={11} fill="var(--text)" fontWeight="700">{d.count} compte{d.count !== 1 ? "s" : ""}</text>
                </g>
              )}
            </g>
          );
        })}
      </svg>
    </div>
  );
}

function StockageComptes() {
  const { useState, useRef, useEffect } = React;
  const store = useAccountStore();
  const accounts = store.list();
  const [syncing, setSyncing] = useState(false);
  const [lastSync, setLastSync] = useState(null);

  useEffect(() => {
    setSyncing(true);
    store.syncFromBackend().then(() => {
      setSyncing(false);
      setLastSync(new Date());
    }).catch(() => setSyncing(false));
  }, []);
  const [q, setQ] = useState("");
  const [toast, setToast] = useState(null);
  const toastRef = useRef(null);
  const [chartDays, setChartDays] = useState(7);
  const [hourMode, setHourMode] = useState(false);
  const [customStart, setCustomStart] = useState("");
  const [cats, setCats] = useState(loadCategories);
  const [catFilter, setCatFilter] = useState("Tous");
  const [newCatInput, setNewCatInput] = useState(false);
  const [newCatVal, setNewCatVal] = useState("");
  const dragCat = React.useRef(null);
  const [dragOver, setDragOver] = React.useState(null);
  const [renamingCat, setRenamingCat] = React.useState(null);
  const [renameVal, setRenameVal] = React.useState("");

  const copyField = (text, label) => {
    if (!text) return;
    try { navigator.clipboard.writeText(text); } catch (_) {}
    if (toastRef.current) clearTimeout(toastRef.current);
    setToast("✓ " + label + " copié");
    toastRef.current = setTimeout(() => setToast(null), 2000);
  };

  const addCategory = () => {
    const v = newCatVal.trim();
    if (!v || cats.some(c => c.label === v)) { setNewCatInput(false); setNewCatVal(""); return; }
    const next = [...cats, { label: v, emoji: "" }];
    saveCategories(next); setCats(next); setNewCatInput(false); setNewCatVal("");
  };

  const deleteCategory = (label) => {
    if (label === "Warm Up") return;
    const next = cats.filter(c => c.label !== label);
    saveCategories(next); setCats(next);
    if (catFilter === label) setCatFilter("Tous");
  };

  const setCatEmoji = (label, emoji) => {
    const next = cats.map(c => c.label === label ? { ...c, emoji } : c);
    saveCategories(next); setCats(next); setEmojiPickerFor(null);
  };

  const startRename = (label) => {
    setRenamingCat(label); setRenameVal(label);
    setEmojiPickerFor(null);
  };

  const commitRename = () => {
    const newLabel = renameVal.trim();
    if (!newLabel || (newLabel !== renamingCat && cats.some(c => c.label === newLabel))) {
      setRenamingCat(null); return;
    }
    if (newLabel === renamingCat) { setRenamingCat(null); return; }
    const next = cats.map(c => c.label === renamingCat ? { ...c, label: newLabel } : c);
    saveCategories(next); setCats(next);
    // mettre à jour les comptes existants
    const all = AccountCreationStore.list().map(a => a.category === renamingCat ? { ...a, category: newLabel } : a);
    try { localStorage.setItem("phonelabs.created_accounts", JSON.stringify(all)); } catch (_) {}
    if (catFilter === renamingCat) setCatFilter(newLabel);
    setRenamingCat(null);
  };

  const setAccountCat = (id, cat) => store.update(id, { category: cat });

  const filtered = accounts.filter(a => {
    const matchQ = !q.trim() || [a.username, a.nom, a.phone, a.device_tag, a.operator].some(f => (f || "").toLowerCase().includes(q.toLowerCase()));
    const matchCat = catFilter === "Tous" || (a.category || "Warm Up") === catFilter;
    return matchQ && matchCat;
  });

  const exportCsv = () => {
    const hdr = "date,operateur,categorie,nom,username,password,telephone,code_2fa,device,birthday\n";
    const rows = accounts.map(a =>
      [a.saved_at?.slice(0, 16)?.replace("T", " "), a.operator, a.category, a.nom, a.username, a.password, a.phone, a.totp_key, a.device_tag, a.birthday].map(v => `"${(v || "").replace(/"/g, '""')}"`).join(",")
    ).join("\n");
    const blob = new Blob([hdr + rows], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const el = document.createElement("a"); el.href = url; el.download = "comptes_ig.csv"; el.click();
    setTimeout(() => URL.revokeObjectURL(url), 3000);
  };

  const TH = ({ children, style }) => <th style={{ textAlign: "left", padding: "10px 12px", fontSize: 11, fontWeight: 700, letterSpacing: ".05em", textTransform: "uppercase", color: "var(--faint)", whiteSpace: "nowrap", ...style }}>{children}</th>;
  const TD = ({ children, style, onClick, title }) => <td onClick={onClick} title={title} style={{ padding: "11px 12px", fontSize: 12.5, borderTop: "1px solid var(--border)", verticalAlign: "middle", ...style }}>{children}</td>;
  const clickCell = { cursor: "pointer", userSelect: "none" };
  const hoverTitle = "Cliquer pour copier";

  // calcul des comptes par période pour les badges %
  const nowMs = Date.now();
  const h24 = _countInRange(accounts, nowMs - 86400000, nowMs);
  const h48prev = _countInRange(accounts, nowMs - 2 * 86400000, nowMs - 86400000);
  const d7 = _countInRange(accounts, nowMs - 7 * 86400000, nowMs);
  const d7prev = _countInRange(accounts, nowMs - 14 * 86400000, nowMs - 7 * 86400000);
  const d14 = _countInRange(accounts, nowMs - 14 * 86400000, nowMs);
  const d14prev = _countInRange(accounts, nowMs - 28 * 86400000, nowMs - 14 * 86400000);
  const d30 = _countInRange(accounts, nowMs - 30 * 86400000, nowMs);
  const d30prev = _countInRange(accounts, nowMs - 60 * 86400000, nowMs - 30 * 86400000);

  const PctBadge = ({ curr, prev }) => {
    const txt = _pctDiff(curr, prev);
    if (!txt) return null;
    const col = _pctColor(curr, prev);
    return <span style={{ fontSize: 10, fontWeight: 700, color: col, marginLeft: 2 }}>{txt}</span>;
  };

  const periodBtn = (label, days, hMode) => {
    const isActive = hMode ? hourMode : (!hourMode && chartDays === days && !customStart);
    return (
      <button onClick={() => { if (hMode) { setHourMode(true); setCustomStart(""); } else { setChartDays(days); setHourMode(false); setCustomStart(""); } }}
        style={{ display: "flex", alignItems: "center", gap: 4, padding: "5px 10px", borderRadius: 7, border: "1px solid " + (isActive ? "var(--accent)" : "var(--border)"), background: isActive ? "var(--accent-soft)" : "var(--surface)", color: isActive ? "var(--accent)" : "var(--muted)", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>
        {label}
        {hMode && <PctBadge curr={h24} prev={h48prev} />}
        {!hMode && days === 7  && <PctBadge curr={d7}  prev={d7prev} />}
        {!hMode && days === 14 && <PctBadge curr={d14} prev={d14prev} />}
        {!hMode && days === 30 && <PctBadge curr={d30} prev={d30prev} />}
      </button>
    );
  };

  return (
    <div style={{ position: "relative" }}>
      {toast && (
        <div style={{ position: "fixed", bottom: 28, left: "50%", transform: "translateX(-50%)", background: "var(--accent)", color: "#06281c", padding: "10px 20px", borderRadius: 10, fontWeight: 700, fontSize: 13.5, zIndex: 9999, boxShadow: "0 4px 20px rgba(0,0,0,.35)", pointerEvents: "none" }}>
          {toast}
        </div>
      )}

      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", flexWrap: "wrap", gap: 14, marginBottom: 18 }}>
        <div>
          <div style={{ fontSize: 21, fontWeight: 800 }}>Stockage de comptes</div>
          <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 4 }}>
            <span style={{ fontSize: 13, color: "var(--faint)" }}>{accounts.length} compte(s) Instagram enregistré(s)</span>
            {syncing && <span style={{ fontSize: 11, color: "var(--accent)", display: "flex", alignItems: "center", gap: 4 }}>
              <span style={{ display: "inline-block", width: 8, height: 8, borderRadius: "50%", background: "var(--accent)", animation: "pulse 1s infinite" }} />sync…
            </span>}
            {!syncing && lastSync && window.Backend && window.Backend.devbase && window.Backend.devbase() && (
              <span style={{ fontSize: 11, color: "var(--faint)" }}>✓ synced {lastSync.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" })}</span>
            )}
          </div>
        </div>
        <button onClick={exportCsv} style={{ display: "flex", alignItems: "center", gap: 7, padding: "9px 16px", borderRadius: 10, background: "var(--surface)", border: "1px solid var(--border)", color: "var(--text)", fontWeight: 600, fontSize: 13, cursor: "pointer" }}>
          {React.createElement(Icon.list, { size: 16 })} Exporter CSV
        </button>
      </div>

      {/* Graphique */}
      <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 14, padding: "14px 18px 8px", marginBottom: 16 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10, flexWrap: "wrap" }}>
          <span style={{ fontSize: 12, fontWeight: 700, color: "var(--muted)", marginRight: 4 }}>
            Créations{catFilter !== "Tous" ? ` — ${catFilter}` : ""}
          </span>
          {periodBtn("24h", 1, true)}{periodBtn("7j", 7)}{periodBtn("14j", 14)}{periodBtn("30j", 30)}
          {!hourMode && (
            <>
              <input type="date" value={customStart} onChange={e => { setCustomStart(e.target.value); if (e.target.value) setChartDays(30); }}
                style={{ marginLeft: 4, padding: "4px 8px", background: "var(--surface)", border: "1px solid " + (customStart ? "var(--accent)" : "var(--border)"), borderRadius: 7, color: "var(--text)", fontSize: 12, cursor: "pointer" }} />
              {customStart && <button onClick={() => setCustomStart("")} style={{ background: "none", border: "none", color: "var(--faint)", cursor: "pointer", fontSize: 12 }}>✕ reset</button>}
            </>
          )}
        </div>
        <CreationsChart accounts={catFilter === "Tous" ? accounts : accounts.filter(a => (a.category || "Warm Up") === catFilter)} days={hourMode ? 24 : chartDays} customStart={customStart} hourMode={hourMode} />
      </div>

      {/* Filtres catégorie (drag-to-reorder + emoji) */}
      <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 12, flexWrap: "wrap" }} onClick={() => setRenamingCat(null)}>
        <button onClick={() => setCatFilter("Tous")}
          style={{ display: "flex", alignItems: "center", gap: 4, padding: "5px 12px", borderRadius: 99, border: "1px solid " + (catFilter === "Tous" ? "var(--accent)" : "var(--border)"), background: catFilter === "Tous" ? "var(--accent-soft)" : "var(--surface)", color: catFilter === "Tous" ? "var(--accent)" : "var(--muted)", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>
          Tous
        </button>
        {cats.map((c, i) => {
          const isDragOver = dragOver === i;
          const isActive = catFilter === c.label;
          const isRenaming = renamingCat === c.label;
          return (
            <div key={c.label} style={{ position: "relative" }}>
              {/* Popup clic droit : renommer + emoji + supprimer */}
              {isRenaming && (
                <div onClick={e => e.stopPropagation()} style={{ position: "absolute", top: "calc(100% + 8px)", left: 0, zIndex: 300, background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 11, padding: 10, boxShadow: "0 8px 28px rgba(0,0,0,.28)", minWidth: 192 }}>
                  {/* Renommer */}
                  <div style={{ fontSize: 10, color: "var(--faint)", letterSpacing: ".06em", textTransform: "uppercase", marginBottom: 5 }}>Renommer</div>
                  <div style={{ display: "flex", gap: 4, marginBottom: 10 }}>
                    <input autoFocus value={renameVal} onChange={e => setRenameVal(e.target.value)}
                      onKeyDown={e => { if (e.key === "Enter") commitRename(); if (e.key === "Escape") setRenamingCat(null); }}
                      style={{ padding: "5px 8px", background: "var(--surface)", border: "1px solid var(--accent)", borderRadius: 6, color: "var(--text)", fontSize: 12, flex: 1, outline: "none" }} />
                    <button onClick={commitRename} style={{ padding: "5px 10px", borderRadius: 6, border: "none", background: "var(--accent)", color: "#06281c", fontSize: 11, fontWeight: 700, cursor: "pointer" }}>OK</button>
                  </div>
                  {/* Emoji */}
                  <div style={{ fontSize: 10, color: "var(--faint)", letterSpacing: ".06em", textTransform: "uppercase", marginBottom: 5 }}>Emoji</div>
                  <div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 2, marginBottom: 10 }}>
                    <button onClick={() => setCatEmoji(c.label, "")} title="Aucun"
                      style={{ fontSize: 13, padding: "3px", borderRadius: 5, border: "1px solid " + (!c.emoji ? "var(--accent)" : "transparent"), background: !c.emoji ? "var(--accent-soft)" : "none", cursor: "pointer", color: "var(--faint)" }}>✕</button>
                    {CAT_EMOJIS.map(e => (
                      <button key={e} onClick={() => setCatEmoji(c.label, e)}
                        style={{ fontSize: 15, padding: "2px", borderRadius: 5, border: "1px solid " + (c.emoji === e ? "var(--accent)" : "transparent"), background: c.emoji === e ? "var(--accent-soft)" : "none", cursor: "pointer" }}>{e}</button>
                    ))}
                  </div>
                  {/* Supprimer */}
                  {c.label !== "Warm Up" && (
                    <>
                      <div style={{ height: 1, background: "var(--border)", margin: "2px 0 8px" }} />
                      <button onClick={() => { deleteCategory(c.label); setRenamingCat(null); }}
                        style={{ width: "100%", padding: "6px", borderRadius: 7, border: "1px solid rgba(255,92,108,.3)", background: "none", color: "var(--danger)", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>
                        Supprimer la catégorie
                      </button>
                    </>
                  )}
                </div>
              )}
              {/* Pill */}
              <div draggable
                onDragStart={() => { dragCat.current = i; }}
                onDragOver={e => { e.preventDefault(); setDragOver(i); }}
                onDragLeave={() => setDragOver(null)}
                onDrop={e => {
                  e.preventDefault();
                  const from = dragCat.current;
                  if (from === null || from === i) { setDragOver(null); return; }
                  const next = [...cats];
                  const [moved] = next.splice(from, 1);
                  next.splice(i, 0, moved);
                  saveCategories(next); setCats(next);
                  dragCat.current = null; setDragOver(null);
                }}
                onDragEnd={() => { dragCat.current = null; setDragOver(null); }}
                onClick={e => { e.stopPropagation(); setCatFilter(c.label); }}
                onContextMenu={e => { e.preventDefault(); e.stopPropagation(); startRename(c.label); }}
                title="Clic gauche : filtrer — Clic droit : modifier"
                style={{ display: "flex", alignItems: "center", gap: 5, padding: "5px 11px", borderRadius: 99, border: "1px solid " + (isDragOver ? "var(--accent)" : isRenaming ? "var(--accent)" : isActive ? "var(--accent)" : "var(--border)"), background: isDragOver ? "var(--accent-soft)" : isRenaming ? "var(--accent-soft)" : isActive ? "var(--accent-soft)" : "var(--surface)", cursor: "pointer", userSelect: "none" }}>
                <span style={{ fontSize: 9, opacity: .3 }}>⠿</span>
                {c.emoji && <span style={{ fontSize: 14, lineHeight: 1 }}>{c.emoji}</span>}
                <span style={{ fontSize: 12, fontWeight: 600, color: isActive ? "var(--accent)" : "var(--muted)" }}>{c.label}</span>
              </div>
            </div>
          );
        })}
        {newCatInput ? (
          <div style={{ display: "flex", gap: 4 }}>
            <input autoFocus value={newCatVal} onChange={e => setNewCatVal(e.target.value)}
              onKeyDown={e => { if (e.key === "Enter") addCategory(); if (e.key === "Escape") { setNewCatInput(false); setNewCatVal(""); } }}
              placeholder="Nom catégorie" style={{ padding: "4px 10px", background: "var(--surface)", border: "1px solid var(--accent)", borderRadius: 7, color: "var(--text)", fontSize: 12, width: 130, outline: "none" }} />
            <button onClick={addCategory} style={{ padding: "4px 10px", borderRadius: 7, border: "1px solid var(--accent)", background: "var(--accent-soft)", color: "var(--accent)", fontSize: 12, fontWeight: 700, cursor: "pointer" }}>OK</button>
          </div>
        ) : (
          <button onClick={() => setNewCatInput(true)} style={{ padding: "5px 12px", borderRadius: 99, border: "1px dashed var(--border)", background: "none", color: "var(--faint)", fontSize: 12, cursor: "pointer" }}>+ Catégorie</button>
        )}
      </div>

      {/* Recherche */}
      <div style={{ display: "flex", gap: 10, marginBottom: 14 }}>
        <div style={{ position: "relative", flex: 1, maxWidth: 340 }}>
          <span style={{ position: "absolute", left: 12, top: "50%", transform: "translateY(-50%)", color: "var(--faint)" }}>{React.createElement(Icon.search, { size: 16 })}</span>
          <input value={q} onChange={e => setQ(e.target.value)} placeholder="Rechercher username, téléphone…" style={{ width: "100%", padding: "9px 12px 9px 36px", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 9, color: "var(--text)", fontSize: 13, outline: "none" }} />
        </div>
      </div>

      {accounts.length === 0 ? (
        <div style={{ textAlign: "center", padding: "70px 0", color: "var(--faint)" }}>
          {React.createElement(Icon.user, { size: 36 })}
          <p style={{ marginTop: 14, fontSize: 13.5 }}>Aucun compte créé pour l'instant. Validez un compte depuis la vue création.</p>
        </div>
      ) : (
        <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 14, overflow: "hidden" }}>
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 760 }}>
              <thead style={{ background: "var(--surface-2)" }}>
                <tr>
                  <TH>Date / heure</TH>
                  <TH>Catégorie</TH>
                  <TH>Opérateur</TH>
                  <TH>Nom</TH>
                  <TH>Username</TH>
                  <TH>Password</TH>
                  <TH>Clé 2FA</TH>
                  <TH>iPhone</TH>
                  <TH style={{ textAlign: "right" }}>Actions</TH>
                </tr>
              </thead>
              <tbody>
                {filtered.map(a => (
                  <tr key={a.id}>
                    <TD>
                      <span className="mono" style={{ fontSize: 11, color: "var(--faint)", whiteSpace: "nowrap" }}>
                        {(a.saved_at || "").slice(0, 16).replace("T", " ")}
                      </span>
                    </TD>
                    <TD>
                      <select value={a.category || "Warm Up"} onChange={e => setAccountCat(a.id, e.target.value)}
                        style={{ background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 6, color: "var(--text)", fontSize: 11.5, padding: "3px 6px", cursor: "pointer" }}>
                        {cats.map(c => <option key={c.label} value={c.label}>{c.emoji ? c.emoji + " " : ""}{c.label}</option>)}
                      </select>
                    </TD>
                    <TD><span style={{ fontSize: 12, color: "var(--muted)" }}>{a.operator || "—"}</span></TD>
                    <TD onClick={() => copyField(a.nom, "Nom")} title={hoverTitle} style={clickCell}>
                      <span style={{ fontWeight: 600 }}>{a.nom || "—"}</span>
                    </TD>
                    <TD onClick={() => copyField(a.username, "Username")} title={hoverTitle} style={clickCell}>
                      <span className="mono" style={{ color: "var(--accent)", fontWeight: 700 }}>@{a.username}</span>
                    </TD>
                    <TD onClick={() => copyField(a.password, "Mot de passe")} title={hoverTitle} style={clickCell}>
                      <span className="mono" style={{ fontSize: 11.5, background: "var(--surface-2)", padding: "3px 8px", borderRadius: 6 }}>{a.password}</span>
                    </TD>
                    <TD onClick={() => copyField(a.totp_key, "Clé 2FA")} title={a.totp_key ? hoverTitle : ""} style={a.totp_key ? clickCell : {}}>
                      {a.totp_key
                        ? <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 11.5, color: "#3b82f6", fontWeight: 700, background: "rgba(59,130,246,.1)", border: "1px solid rgba(59,130,246,.25)", borderRadius: 6, padding: "2px 8px" }}>
                            ✓ 2FA <span className="mono" style={{ fontSize: 10, color: "#60a5fa", fontWeight: 400 }}>{a.totp_key.replace(/\s/g,"").slice(0,8)}…</span>
                          </span>
                        : <span style={{ color: "var(--faint)" }}>—</span>}
                    </TD>
                    <TD><span style={{ fontSize: 12, color: "var(--muted)" }}>{a.device_tag || "—"}</span></TD>
                    <TD style={{ textAlign: "right", whiteSpace: "nowrap" }}>
                      <button onClick={() => copyField(`@${a.username}\nMot de passe: ${a.password}${a.totp_key ? "\n2FA: " + a.totp_key : ""}`, "Compte complet")}
                        title="Tout copier" style={{ background: "var(--surface-2)", border: "1px solid var(--border)", borderRadius: 7, width: 30, height: 30, cursor: "pointer", fontSize: 14 }}>📋</button>
                      <button onClick={() => { if (window.confirm("Supprimer ce compte de la liste ?")) store.remove(a.id); }}
                        title="Supprimer" style={{ marginLeft: 5, background: "none", border: "1px solid rgba(255,92,108,.25)", borderRadius: 7, width: 30, height: 30, cursor: "pointer", color: "var(--danger)", fontWeight: 700 }}>✕</button>
                    </TD>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { AccountCreationStore, useAccountStore, CreationLeftPanel, CreationRemote, StockageComptes, IpRotationBar, NumberSlide, TwoFASlide, CREATION_STEPS });
