// ─────────────────────────────────────────────────────────────────────────
// admin.jsx — Comprehensive admin panel with secure login
// Tile manager, articles CMS, bank rates editor, FX editor, AI generator,
// theme/colors, navigation, footer content, ad slots, inbox, auto-update
// ─────────────────────────────────────────────────────────────────────────

const { useState: useStateA, useEffect: useEffectA, useRef: useRefA, useMemo: useMemoA } = React;

const ADMIN_API_BASE = "/api/admin";
let adminCsrfToken = null;

async function getAdminCsrf() {
  if (adminCsrfToken) return adminCsrfToken;
  const res = await fetch(`${ADMIN_API_BASE}/csrf.php`, { credentials: "include" });
  const data = await res.json().catch(() => ({}));
  if (!res.ok || !data.csrf) {
    throw new Error(data.error || "Nie udalo sie pobrac tokenu bezpieczenstwa.");
  }
  adminCsrfToken = data.csrf;
  return adminCsrfToken;
}

async function adminFetch(path, options = {}) {
  const method = (options.method || "GET").toUpperCase();
  const headers = { ...(options.headers || {}) };
  if (method !== "GET") {
    headers["Content-Type"] = "application/json";
    headers["X-CSRF-Token"] = await getAdminCsrf();
  }
  const res = await fetch(`${ADMIN_API_BASE}${path}`, {
    ...options,
    method,
    headers,
    credentials: "include",
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) {
    throw new Error(data.error || `Blad API (${res.status}).`);
  }
  return data;
}

function isStrongAdminPassword(password) {
  return password.length >= 16
    && /[A-Z]/.test(password)
    && /[a-z]/.test(password)
    && /[0-9]/.test(password)
    && /[^A-Za-z0-9]/.test(password);
}

function AdminSetup({ onInstalled }) {
  const [form, setForm] = useStateA({ username: "admin", password: "", confirm: "" });
  const [error, setError] = useStateA("");
  const [pending, setPending] = useStateA(false);
  const [showPw, setShowPw] = useStateA(false);

  const submit = async (e) => {
    e.preventDefault();
    if (pending) return;
    setError("");
    if (!isStrongAdminPassword(form.password)) {
      setError("Haslo musi miec min. 16 znakow oraz duza litere, mala litere, cyfre i znak specjalny.");
      return;
    }
    if (form.password !== form.confirm) {
      setError("Hasla nie sa takie same.");
      return;
    }
    setPending(true);
    try {
      await adminFetch("/install.php", {
        method: "POST",
        body: JSON.stringify({
          username: form.username,
          password: form.password,
          password_confirm: form.confirm,
        }),
      });
      onInstalled(form.username);
    } catch (err) {
      setError(err.message || "Nie udalo sie utworzyc konta admina.");
    } finally {
      setPending(false);
    }
  };

  return (
    <div className="container" style={{ display: "flex", alignItems: "center", justifyContent: "center", minHeight: "70vh" }}>
      <div className="card" style={{ width: "min(500px, 100%)", padding: 36, border: "1px solid var(--accent)" }}>
        <div style={{ fontSize: 11, fontWeight: 800, color: "var(--accent)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 8 }}>Pierwsza konfiguracja</div>
        <h1 style={{ margin: 0, fontSize: 24, fontWeight: 850 }}>Utworz konto admina</h1>
        <p style={{ fontSize: 13, color: "var(--text-2)", lineHeight: 1.55, margin: "12px 0 24px" }}>
          Konto zostanie zapisane w bazie MySQL jako bcrypt + pepper. Po zapisaniu endpoint instalacyjny sam sie zablokuje.
        </p>

        <form onSubmit={submit}>
          <Field label="Login administratora">
            <input className="input" value={form.username} onChange={e => setForm({ ...form, username: e.target.value })} autoComplete="username" required />
          </Field>
          <Field label="Haslo administratora">
            <div style={{ position: "relative" }}>
              <input
                type={showPw ? "text" : "password"}
                className="input"
                value={form.password}
                onChange={e => setForm({ ...form, password: e.target.value })}
                autoComplete="new-password"
                required
                style={{ paddingRight: 56, fontFamily: "var(--font-mono)" }}
              />
              <button type="button" onClick={() => setShowPw(p => !p)}
                style={{ position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", background: "transparent", border: "none", color: "var(--text-3)", cursor: "pointer", padding: 6, fontSize: 12 }}>
                {showPw ? "Ukryj" : "Pokaz"}
              </button>
            </div>
          </Field>
          <Field label="Powtorz haslo">
            <input type={showPw ? "text" : "password"} className="input" value={form.confirm} onChange={e => setForm({ ...form, confirm: e.target.value })} autoComplete="new-password" required style={{ fontFamily: "var(--font-mono)" }} />
          </Field>

          {error && (
            <div style={{ marginTop: 12, padding: "10px 14px", background: "color-mix(in oklch, var(--bad) 15%, transparent)", border: "1px solid var(--bad)", borderRadius: 10, color: "var(--bad)", fontSize: 12, fontWeight: 650 }}>
              {error}
            </div>
          )}

          <button type="submit" className="btn btn-primary" disabled={pending} style={{ marginTop: 18, width: "100%", justifyContent: "center", padding: "14px 22px" }}>
            {pending ? "Tworze konto..." : "Utworz bezpieczne konto"}
          </button>
        </form>
      </div>
    </div>
  );
}

function AdminLogin({ onLogin, initialUsername = "admin" }) {
  const [username, setUsername] = useStateA(initialUsername);
  const [password, setPassword] = useStateA("");
  const [totp, setTotp] = useStateA("");
  const [totpRequired, setTotpRequired] = useStateA(false);
  const [error, setError] = useStateA("");
  const [pending, setPending] = useStateA(false);
  const [showPw, setShowPw] = useStateA(false);
  const [attempts, setAttempts] = useStateA(0);

  const submit = async (e) => {
    e.preventDefault();
    if (pending) return;
    setPending(true);
    setError("");
    try {
      const data = await adminFetch("/login.php", {
        method: "POST",
        body: JSON.stringify({ username, password, totp }),
      });
      if (data.totp_required) {
        setTotpRequired(true);
        setError("Podaj kod 2FA z aplikacji uwierzytelniajacej.");
        return;
      }
      onLogin();
    } catch (err) {
      setAttempts(a => a + 1);
      setError(err.message || "Blad uwierzytelniania.");
      setPassword("");
    } finally {
      setPending(false);
    }
  };

  return (
    <div className="container" style={{ display: "flex", alignItems: "center", justifyContent: "center", minHeight: "70vh" }}>
      <div className="card" style={{ width: "min(460px, 100%)", padding: 36, background: "linear-gradient(155deg, var(--accent-soft), transparent 60%), var(--surface)", border: "1px solid var(--accent)" }}>
        <div style={{ fontSize: 11, fontWeight: 800, color: "var(--accent)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 8 }}>Panel admina</div>
        <h1 style={{ margin: 0, fontSize: 24, fontWeight: 850 }}>KreditEU</h1>
        <p style={{ fontSize: 13, color: "var(--text-2)", lineHeight: 1.55, margin: "12px 0 24px" }}>
          Logowanie dziala przez bezpieczna sesje backendu, CSRF i haslo bcrypt zapisane w MySQL.
        </p>

        <form onSubmit={submit}>
          <Field label="Login administratora">
            <input className="input" value={username} onChange={e => setUsername(e.target.value)} autoComplete="username" required />
          </Field>
          <Field label="Haslo administratora">
            <div style={{ position: "relative" }}>
              <input
                type={showPw ? "text" : "password"}
                className="input"
                value={password}
                onChange={e => setPassword(e.target.value)}
                autoComplete="current-password"
                required
                style={{ paddingRight: 56, fontFamily: "var(--font-mono)" }}
              />
              <button type="button" onClick={() => setShowPw(p => !p)}
                style={{ position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", background: "transparent", border: "none", color: "var(--text-3)", cursor: "pointer", padding: 6, fontSize: 12 }}>
                {showPw ? "Ukryj" : "Pokaz"}
              </button>
            </div>
          </Field>
          {totpRequired && (
            <Field label="Kod 2FA">
              <input className="input" value={totp} onChange={e => setTotp(e.target.value)} inputMode="numeric" autoComplete="one-time-code" placeholder="123456" />
            </Field>
          )}

          {error && (
            <div style={{ marginTop: 12, padding: "10px 14px", background: "color-mix(in oklch, var(--bad) 15%, transparent)", border: "1px solid var(--bad)", borderRadius: 10, color: "var(--bad)", fontSize: 12, fontWeight: 650 }}>
              {error}
            </div>
          )}

          <button type="submit" className="btn btn-primary" disabled={pending || !username || !password} style={{ marginTop: 18, width: "100%", justifyContent: "center", padding: "14px 22px" }}>
            {pending ? "Sprawdzam..." : "Zaloguj sie"}
          </button>
        </form>

        {attempts >= 3 && (
          <div style={{ marginTop: 16, padding: "10px 14px", background: "color-mix(in oklch, var(--warn) 14%, transparent)", border: "1px solid var(--warn)", borderRadius: 10, fontSize: 11, color: "var(--warn)", textAlign: "center" }}>
            Pozostale proby przed blokada IP: {Math.max(0, 5 - attempts)}
          </div>
        )}
      </div>
    </div>
  );
}

function AdminPage({ navigate, tiles, setTiles, tweaks, setTweak }) {
  const [auth, setAuth] = useStateA({ loading: true, authed: false, installed: true, username: "admin", error: "" });

  const refreshAuth = async () => {
    setAuth(a => ({ ...a, loading: true, error: "" }));
    try {
      const status = await adminFetch("/status.php");
      if (!status.installed) {
        setAuth({ loading: false, authed: false, installed: false, username: "admin", error: "" });
        return;
      }
      const me = await adminFetch("/me.php");
      setAuth({
        loading: false,
        authed: !!me.authenticated,
        installed: true,
        username: me.user?.username || "admin",
        error: "",
      });
    } catch (err) {
      setAuth({ loading: false, authed: false, installed: true, username: "admin", error: err.message || "Nie udalo sie sprawdzic sesji." });
    }
  };

  useEffectA(() => { refreshAuth(); }, []);

  if (auth.loading) {
    return (
      <div className="container" style={{ minHeight: "60vh", display: "grid", placeItems: "center" }}>
        <div className="card" style={{ padding: 24, fontWeight: 750 }}>Sprawdzam sesje admina...</div>
      </div>
    );
  }

  if (!auth.installed) {
    return <AdminSetup onInstalled={(username) => setAuth({ loading: false, authed: false, installed: true, username, error: "" })} />;
  }

  if (!auth.authed) {
    return (
      <>
        {auth.error && (
          <div className="container" style={{ paddingTop: 18 }}>
            <div className="card" style={{ padding: 14, borderColor: "var(--warn)", color: "var(--warn)", fontSize: 12 }}>{auth.error}</div>
          </div>
        )}
        <AdminLogin initialUsername={auth.username} onLogin={refreshAuth} />
      </>
    );
  }

  const logout = async () => {
    try {
      await adminFetch("/logout.php", { method: "POST", body: "{}" });
    } catch {}
    adminCsrfToken = null;
    setAuth(a => ({ ...a, authed: false }));
  };

  return <AdminShell navigate={navigate} tiles={tiles} setTiles={setTiles} tweaks={tweaks} setTweak={setTweak} logout={logout} />;
}

function AdminShell({ navigate, tiles, setTiles, tweaks, setTweak, logout }) {
  const [tab, setTab] = useStateA("dashboard");
  const [inbox, setInbox] = useStateA(() => {
    try { return JSON.parse(localStorage.getItem("kr_inbox") || "[]"); } catch { return []; }
  });

  // Refresh inbox count periodically
  useEffectA(() => {
    const sync = () => {
      try { setInbox(JSON.parse(localStorage.getItem("kr_inbox") || "[]")); } catch {}
    };
    const id = setInterval(sync, 2000);
    window.addEventListener("storage", sync);
    return () => { clearInterval(id); window.removeEventListener("storage", sync); };
  }, []);

  const unreadCount = inbox.filter(m => m.status === "new").length;

  const tabs = [
    { k: "dashboard", l: "📊 Dashboard", desc: "Przegląd serwisu" },
    { k: "tiles",     l: "🧩 Kafelki",   desc: "Drag & drop, edycja" },
    { k: "articles",  l: "📝 Artykuły",  desc: "CMS, generator AI obrazów" },
    { k: "ai",        l: "🤖 Generator AI", desc: "Claude / Gemini" },
    { k: "banks",     l: "🏦 Oprocentowanie", desc: "Edycja stóp banków" },
    { k: "fx",        l: "💱 Kursy walut", desc: "NBP / ECB" },
    { k: "autoupdate",l: "🔄 Auto-update", desc: "Tygodniowy harmonogram" },
    { k: "inbox",     l: "📬 Skrzynka",    desc: "Wiadomości od użytkowników", badge: unreadCount },
    { k: "theme",     l: "🎨 Motyw", desc: "Kolory i layout" },
    { k: "ads",       l: "📢 Reklamy", desc: "Slot AdSense" },
    { k: "i18n",      l: "🌐 Języki", desc: "PL · EN · DE · FR …" },
    { k: "settings",  l: "⚙️ Ustawienia", desc: "Hasło, API keys" },
  ];

  return (
    <div className="container">
      <Breadcrumbs items={[{ label: "Strona główna", route: "home" }, { label: "Panel admina" }]} navigate={navigate} />

      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 24, flexWrap: "wrap", gap: 16 }}>
        <div>
          <div style={{ fontSize: 11, fontWeight: 700, color: "var(--accent)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 8 }}>⚙️ Panel admina</div>
          <h1 style={{ margin: 0, fontSize: "clamp(28px, 4vw, 40px)", fontWeight: 800, letterSpacing: "-0.025em" }}>
            Zarządzaj <span style={{ color: "var(--accent)" }}>KreditEU</span>
          </h1>
        </div>
        <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
          <span className="chip"><span className="live-dot" /> Sesja aktywna</span>
          <button className="btn btn-soft" onClick={() => navigate("home")}>← Podgląd</button>
          <button className="btn btn-soft" onClick={logout} style={{ color: "var(--bad)" }}>🚪 Wyloguj</button>
        </div>
      </div>

      {/* Stats strip */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))", gap: 12, marginBottom: 24 }}>
        <AdminStat value={window.ARTICLES.length} label="Artykułów" tone="default" />
        <AdminStat value={window.BANKS.length} label="Banków" tone="default" />
        <AdminStat value={window.COUNTRIES.length} label="Krajów EU" tone="default" />
        <AdminStat value={tiles.length} label="Kafelków" tone="accent" />
        <AdminStat value={inbox.length} label="Wiadomości" tone={unreadCount > 0 ? "accent" : "default"} />
        <AdminStat value={unreadCount} label="Nieprzeczytane" tone={unreadCount > 0 ? "warn" : "muted"} />
      </div>

      {/* Layout: sidebar + content */}
      <div style={{ display: "grid", gridTemplateColumns: "240px 1fr", gap: 24 }} className="kr-admin-grid">
        <aside className="card" style={{ padding: 8, alignSelf: "flex-start", position: "sticky", top: 100 }}>
          {tabs.map(t => (
            <button key={t.k} onClick={() => setTab(t.k)} style={{
              display: "flex", width: "100%",
              flexDirection: "column", alignItems: "flex-start",
              padding: "10px 12px",
              background: tab === t.k ? "var(--surface-2)" : "transparent",
              border: "1px solid " + (tab === t.k ? "var(--border)" : "transparent"),
              borderRadius: 10,
              color: tab === t.k ? "var(--text)" : "var(--text-2)",
              cursor: "pointer", marginBottom: 2,
              textAlign: "left", position: "relative",
              transition: "all 0.14s",
            }}>
              <span style={{ fontSize: 13, fontWeight: 700, display: "flex", alignItems: "center", gap: 8 }}>
                {t.l}
                {t.badge > 0 && (
                  <span style={{
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    minWidth: 18, height: 18, padding: "0 6px",
                    background: "var(--bad)", color: "white", borderRadius: 999,
                    fontSize: 10, fontWeight: 800,
                  }}>{t.badge}</span>
                )}
              </span>
              <span style={{ fontSize: 10, color: "var(--text-3)" }}>{t.desc}</span>
            </button>
          ))}
        </aside>

        <main style={{ minWidth: 0 }}>
          {tab === "dashboard"  && <AdminDashboard tiles={tiles} navigate={navigate} setTab={setTab} unread={unreadCount} />}
          {tab === "tiles"      && <AdminTiles tiles={tiles} setTiles={setTiles} />}
          {tab === "articles"   && <AdminArticles navigate={navigate} />}
          {tab === "ai"         && <AdminAI openArticles={() => setTab("articles")} />}
          {tab === "banks"      && <AdminBanks />}
          {tab === "fx"         && <AdminFX />}
          {tab === "autoupdate" && <AdminAutoUpdate />}
          {tab === "inbox"      && <AdminInbox inbox={inbox} setInbox={setInbox} />}
          {tab === "theme"      && <AdminTheme tweaks={tweaks} setTweak={setTweak} />}
          {tab === "ads"        && <AdminAds />}
          {tab === "i18n"       && <AdminI18n />}
          {tab === "settings"   && <AdminSettings />}
        </main>
      </div>
    </div>
  );
}

function AdminStat({ value, label, tone }) {
  const colors = {
    accent: { bg: "var(--accent-soft)", text: "var(--accent)" },
    warn:   { bg: "color-mix(in oklch, var(--warn) 14%, var(--surface))", text: "var(--warn)" },
    default: { bg: "var(--surface)", text: "var(--text)" },
    muted: { bg: "var(--surface)", text: "var(--text-3)" },
  };
  const c = colors[tone] || colors.default;
  return (
    <div className="card" style={{ padding: 16, background: c.bg, border: "1px solid var(--border-soft)" }}>
      <div className="num-mono" style={{ fontSize: 28, fontWeight: 800, color: c.text }}>{value}</div>
      <div style={{ fontSize: 10, fontWeight: 700, color: "var(--text-3)", textTransform: "uppercase", letterSpacing: "0.08em", marginTop: 4 }}>{label}</div>
    </div>
  );
}

/* ────────── Dashboard ────────── */
function AdminDashboard({ tiles, navigate, setTab, unread = 0 }) {
  return (
    <div>
      <SectionHeader title="Dashboard" desc="Skróty do najczęściej używanych funkcji" />

      {unread > 0 && (
        <div className="card" style={{
          padding: 16, marginBottom: 16,
          background: "linear-gradient(155deg, var(--accent-soft), transparent), var(--surface)",
          border: "1px solid var(--accent)",
          display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 12,
        }}>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--accent)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 4 }}>📬 Nowe wiadomości</div>
            <div style={{ fontSize: 16, fontWeight: 700 }}>
              Masz <span className="num-mono" style={{ color: "var(--accent)" }}>{unread}</span> {unread === 1 ? "nieprzeczytaną wiadomość" : "nieprzeczytanych wiadomości"} w skrzynce
            </div>
          </div>
          <button className="btn btn-primary" onClick={() => setTab("inbox")}>Otwórz skrzynkę →</button>
        </div>
      )}

      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))", gap: 16 }}>
        {[
          { i: "📝", t: "Dodaj artykuł", d: "Ręcznie + zdjęcie AI", a: () => setTab("articles") },
          { i: "🧩", t: "Edytuj kafelki", d: "Zmień układ home page", a: () => setTab("tiles") },
          { i: "🏦", t: "Zaktualizuj oprocentowanie", d: "Stopy banków", a: () => setTab("banks") },
          { i: "🔄", t: "Auto-update", d: "Harmonogram tygodniowy", a: () => setTab("autoupdate") },
          { i: "💱", t: "Pobierz kursy NBP", d: "Aktualne dane FX", a: () => setTab("fx") },
          { i: "📬", t: "Skrzynka", d: unread > 0 ? `${unread} nowych wiadomości` : "Wszystko przeczytane", a: () => setTab("inbox") },
          { i: "🎨", t: "Zmień motyw", d: "Kolory, ciemny/jasny", a: () => setTab("theme") },
          { i: "🤖", t: "Generuj AI", d: "Artykuł z Claude/Gemini", a: () => setTab("ai") },
        ].map((s, i) => (
          <button key={i} onClick={s.a} className="card card-hover" style={{
            padding: 20, textAlign: "left", cursor: "pointer", border: "1px solid var(--border-soft)",
            background: "var(--surface)",
          }}>
            <div style={{ fontSize: 28, marginBottom: 10 }}>{s.i}</div>
            <h4 style={{ margin: 0, fontSize: 14, fontWeight: 800 }}>{s.t}</h4>
            <p style={{ marginTop: 4, fontSize: 12, color: "var(--text-2)" }}>{s.d}</p>
          </button>
        ))}
      </div>

      <div style={{ marginTop: 32 }}>
        <SectionHeader title="Aktualności AI" desc="Codzienna analiza zmian oprocentowania" />
        <div className="card" style={{ padding: 20 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 12 }}>
            <span style={{ fontSize: 13, fontWeight: 700 }}>📰 Ostatnia aktualizacja: 12.05.2026 06:00</span>
            <button className="btn btn-soft" style={{ fontSize: 11 }}>🔄 Odśwież AI</button>
          </div>
          <ul style={{ margin: 0, paddingLeft: 18, color: "var(--text-2)", fontSize: 13, lineHeight: 1.7 }}>
            <li>PKO BP obniżył oprocentowanie kredytów hipotecznych o 0.10 pp do <strong>6.49%</strong></li>
            <li>EBC pozostawił stopy bez zmian — EURIBOR 3M ustabilizował się na 2.61%</li>
            <li>Santander podwyższył marżę kredytów gotówkowych o 0.15 pp</li>
            <li>Nowy program: Bezpieczny Kredyt 2% wystartuje od 1 lipca 2026</li>
          </ul>
        </div>
      </div>
    </div>
  );
}

/* ────────── Tiles editor — drag & drop ────────── */
function AdminTiles({ tiles, setTiles }) {
  const [editing, setEditing] = useStateA(null);
  const dragIdx = useRefA(null);

  const handleDragStart = (i) => { dragIdx.current = i; };
  const handleDragOver = (e) => e.preventDefault();
  const handleDrop = (i) => {
    if (dragIdx.current === null) return;
    const next = [...tiles];
    const [moved] = next.splice(dragIdx.current, 1);
    next.splice(i, 0, moved);
    setTiles(next);
    dragIdx.current = null;
  };

  const updateTile = (id, patch) => setTiles(tiles.map(t => t.id === id ? { ...t, ...patch } : t));
  const deleteTile = (id) => setTiles(tiles.filter(t => t.id !== id));
  const addTile = () => {
    const id = "custom-" + Math.random().toString(36).slice(2, 7);
    setTiles([...tiles, { id, kind: "ai", size: "md", title: "Nowy kafelek", sub: "Edytuj treść" }]);
    setEditing(id);
  };
  const resetTiles = () => setTiles([...window.DEFAULT_TILES]);

  return (
    <div>
      <SectionHeader title="Kafelki na stronie głównej"
        desc="Przeciągnij kafelek, by zmienić kolejność. Kliknij ✎ aby edytować tytuł i rozmiar."
        action={
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn btn-soft" onClick={resetTiles}>↺ Reset</button>
            <button className="btn btn-primary" onClick={addTile}>+ Dodaj kafelek</button>
          </div>
        }
      />

      <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
        {tiles.map((t, i) => (
          <div key={t.id}
            draggable
            onDragStart={() => handleDragStart(i)}
            onDragOver={handleDragOver}
            onDrop={() => handleDrop(i)}
            style={{
              display: "grid",
              gridTemplateColumns: "auto 1fr auto auto auto auto",
              gap: 12, alignItems: "center",
              padding: 14,
              background: editing === t.id ? "var(--surface-2)" : "var(--surface)",
              border: "1px solid " + (editing === t.id ? "var(--accent)" : "var(--border-soft)"),
              borderRadius: 12, cursor: "grab",
            }}
          >
            <span style={{ color: "var(--text-3)", fontSize: 14, padding: "0 4px" }}>⋮⋮</span>
            <div>
              {editing === t.id ? (
                <input className="input" value={t.title} onChange={e => updateTile(t.id, { title: e.target.value })}
                  style={{ padding: "6px 10px", fontSize: 13 }} />
              ) : (
                <div>
                  <div style={{ fontSize: 13, fontWeight: 700 }}>{t.title}</div>
                  {t.sub && <div style={{ fontSize: 11, color: "var(--text-3)" }}>{t.sub}</div>}
                </div>
              )}
            </div>
            <span className="chip" style={{ fontSize: 10, padding: "2px 8px" }}>{t.kind}</span>
            <select className="select" value={t.size} onChange={e => updateTile(t.id, { size: e.target.value })}
              style={{ padding: "6px 10px", fontSize: 12, width: "auto" }}>
              <option value="sm">SM</option>
              <option value="md">MD</option>
              <option value="lg">LG</option>
              <option value="xl">XL</option>
            </select>
            <button onClick={() => setEditing(editing === t.id ? null : t.id)} style={iconBtn2()}>{editing === t.id ? "✓" : "✎"}</button>
            <button onClick={() => deleteTile(t.id)} style={{ ...iconBtn2(), color: "var(--bad)" }}>🗑</button>
          </div>
        ))}
      </div>

      <p style={{ marginTop: 16, fontSize: 11, color: "var(--text-3)" }}>
        💡 Zmiany zapisują się automatycznie i widać je na stronie głównej w czasie rzeczywistym.
      </p>
    </div>
  );
}

function iconBtn2() {
  return {
    width: 32, height: 32, display: "inline-flex", alignItems: "center", justifyContent: "center",
    background: "var(--bg-2)", border: "1px solid var(--border-soft)", borderRadius: 8,
    color: "var(--text-2)", cursor: "pointer", fontSize: 12,
  };
}

/* ────────── Inbox (internal messages from contact form) ────────── */
function AdminInbox({ inbox, setInbox }) {
  const [selected, setSelected] = useStateA(inbox[0] || null);
  const [filter, setFilter] = useStateA("all");
  const [search, setSearch] = useStateA("");

  // Sync to localStorage
  const updateMessages = (next) => {
    setInbox(next);
    localStorage.setItem("kr_inbox", JSON.stringify(next));
  };

  const markStatus = (id, status) => {
    updateMessages(inbox.map(m => m.id === id ? { ...m, status } : m));
    if (selected && selected.id === id) setSelected({ ...selected, status });
  };

  const deleteMessage = (id) => {
    if (!confirm("Usunąć wiadomość?")) return;
    const next = inbox.filter(m => m.id !== id);
    updateMessages(next);
    if (selected && selected.id === id) setSelected(next[0] || null);
  };

  const insertDemo = () => {
    const demos = [
      { id: Date.now() + 1, name: "Anna Kowalska", email: "anna@example.com", topic: "general", msg: "Dzień dobry, mam pytanie odnośnie kalkulatora hipotecznego. Jak wprowadzić oprocentowanie zmienne? Pozdrawiam.", date: new Date().toISOString(), status: "new" },
      { id: Date.now() + 2, name: "Tomasz Nowak", email: "tomasz.nowak@firma.pl", topic: "ads", msg: "Witam, jesteśmy zainteresowani współpracą reklamową na Państwa stronie. Prosimy o kontakt zwrotny w sprawie cennika.", date: new Date(Date.now() - 3600000).toISOString(), status: "new" },
      { id: Date.now() + 3, name: "Piotr Wiśniewski", email: "p.wisniewski@gmail.com", topic: "bug", msg: "Kalkulator nieprawidłowo przelicza ratę dla okresu 30 lat. Sprawdziłem w Excelu i wychodzą inne wartości.", date: new Date(Date.now() - 86400000).toISOString(), status: "read" },
    ];
    const next = [...demos, ...inbox];
    updateMessages(next);
    setSelected(demos[0]);
  };

  const filtered = inbox.filter(m => {
    if (filter !== "all" && m.status !== filter) return false;
    if (search && !(m.name.toLowerCase().includes(search.toLowerCase()) || m.email.toLowerCase().includes(search.toLowerCase()) || m.msg.toLowerCase().includes(search.toLowerCase()))) return false;
    return true;
  });

  const topicLabels = {
    general: "Pytanie ogólne",
    bug: "Zgłoszenie błędu",
    ads: "Reklama / partnerstwo",
    rodo: "Usunięcie danych (RODO)",
  };

  return (
    <div>
      <SectionHeader
        title="📬 Wewnętrzna skrzynka"
        desc="Wiadomości z formularza kontaktowego trafiają tutaj — nie na zewnętrznego maila"
        action={
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn btn-soft" onClick={insertDemo}>+ Demo</button>
            <button className="btn btn-soft" onClick={() => { if (confirm("Wyczyścić całą skrzynkę?")) updateMessages([]); }}>🗑 Wyczyść</button>
          </div>
        }
      />

      <div style={{ display: "grid", gridTemplateColumns: "minmax(280px, 380px) 1fr", gap: 16, minHeight: 540 }} className="kr-admin-grid">
        {/* List */}
        <div className="card" style={{ padding: 0, display: "flex", flexDirection: "column", overflow: "hidden" }}>
          <div style={{ padding: 12, borderBottom: "1px solid var(--border-soft)", display: "flex", gap: 6, flexWrap: "wrap" }}>
            <input className="input" placeholder="Szukaj…" value={search} onChange={e => setSearch(e.target.value)}
              style={{ flex: "1 1 100%", padding: "8px 12px", fontSize: 12, marginBottom: 8 }} />
            {[["all", "Wszystkie", inbox.length],
              ["new", "Nowe", inbox.filter(m => m.status === "new").length],
              ["read", "Przeczytane", inbox.filter(m => m.status === "read").length],
              ["replied", "Odpowiedziane", inbox.filter(m => m.status === "replied").length]].map(([k, l, n]) => (
              <button key={k} onClick={() => setFilter(k)} style={{
                padding: "4px 10px", fontSize: 11, fontWeight: 700,
                background: filter === k ? "var(--accent)" : "var(--bg-2)",
                color: filter === k ? "var(--bg)" : "var(--text-2)",
                border: "none", borderRadius: 999, cursor: "pointer",
              }}>{l} <span style={{ opacity: 0.7 }}>({n})</span></button>
            ))}
          </div>
          <div style={{ flex: 1, overflowY: "auto" }}>
            {filtered.length === 0 && (
              <div style={{ padding: 40, textAlign: "center", color: "var(--text-3)" }}>
                <div style={{ fontSize: 40, marginBottom: 12 }}>📭</div>
                <div style={{ fontSize: 13 }}>{inbox.length === 0 ? "Skrzynka pusta" : "Brak wyników"}</div>
                {inbox.length === 0 && <div style={{ fontSize: 11, marginTop: 8 }}>Wiadomości z formularza pojawią się tu automatycznie.</div>}
              </div>
            )}
            {filtered.map(m => (
              <button key={m.id} onClick={() => { setSelected(m); if (m.status === "new") markStatus(m.id, "read"); }}
                style={{
                  display: "block", width: "100%", textAlign: "left",
                  padding: "14px 16px",
                  background: selected && selected.id === m.id ? "var(--surface-2)" : "transparent",
                  border: "none", borderBottom: "1px solid var(--border-soft)",
                  cursor: "pointer",
                  position: "relative",
                }}>
                {m.status === "new" && <span style={{ position: "absolute", top: 14, right: 14, width: 8, height: 8, borderRadius: "50%", background: "var(--accent)" }} />}
                <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                  <span style={{ fontSize: 13, fontWeight: m.status === "new" ? 800 : 600, color: "var(--text)" }}>{m.name}</span>
                  <span style={{ fontSize: 10, color: "var(--text-3)" }}>{formatRel(m.date)}</span>
                </div>
                <div style={{ fontSize: 11, color: "var(--accent)", fontWeight: 700, marginBottom: 4 }}>{topicLabels[m.topic] || m.topic}</div>
                <div style={{ fontSize: 12, color: "var(--text-2)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{m.msg}</div>
              </button>
            ))}
          </div>
        </div>

        {/* Preview */}
        <div className="card" style={{ padding: selected ? 24 : 0, minHeight: 540, display: "flex", flexDirection: "column" }}>
          {!selected ? (
            <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", color: "var(--text-3)" }}>
              <div style={{ fontSize: 48, marginBottom: 12 }}>✉️</div>
              <div style={{ fontSize: 14 }}>Wybierz wiadomość, aby ją przeczytać</div>
            </div>
          ) : (
            <>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 16, flexWrap: "wrap", gap: 12 }}>
                <div>
                  <div style={{ fontSize: 11, fontWeight: 700, color: "var(--accent)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 4 }}>
                    {topicLabels[selected.topic] || selected.topic}
                  </div>
                  <h3 style={{ margin: 0, fontSize: 20, fontWeight: 800 }}>{selected.name}</h3>
                  <div style={{ fontSize: 13, color: "var(--text-2)", marginTop: 4 }}>
                    <a href={`mailto:${selected.email}`} style={{ color: "var(--accent)" }}>{selected.email}</a>
                    <span style={{ marginLeft: 12, color: "var(--text-3)" }}>{new Date(selected.date).toLocaleString("pl-PL")}</span>
                  </div>
                </div>
                <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                  <span className="chip" style={{ fontSize: 10 }}>
                    {selected.status === "new" ? "🟡 Nowa" : selected.status === "read" ? "🔵 Przeczytana" : "🟢 Odpowiedziana"}
                  </span>
                </div>
              </div>

              <div style={{
                flex: 1,
                padding: 20,
                background: "var(--bg-2)",
                borderRadius: 12,
                fontSize: 14, lineHeight: 1.6, color: "var(--text)",
                whiteSpace: "pre-wrap",
                marginBottom: 16,
              }}>
                {selected.msg}
              </div>

              <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                <a href={`mailto:${selected.email}?subject=Re: KreditEU&body=Dzień dobry,%0D%0A%0D%0A`} className="btn btn-primary"
                  onClick={() => markStatus(selected.id, "replied")}>
                  ↩ Odpowiedz przez email
                </a>
                {selected.status !== "replied" && (
                  <button className="btn btn-soft" onClick={() => markStatus(selected.id, "replied")}>✓ Oznacz jako odpowiedziane</button>
                )}
                {selected.status === "new" && (
                  <button className="btn btn-soft" onClick={() => markStatus(selected.id, "read")}>👁 Oznacz jako przeczytane</button>
                )}
                <button className="btn btn-soft" onClick={() => deleteMessage(selected.id)} style={{ color: "var(--bad)" }}>🗑 Usuń</button>
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

function formatRel(iso) {
  const ms = Date.now() - new Date(iso).getTime();
  const m = Math.floor(ms / 60000);
  if (m < 1) return "teraz";
  if (m < 60) return m + " min";
  const h = Math.floor(m / 60);
  if (h < 24) return h + " godz.";
  const d = Math.floor(h / 24);
  if (d < 7) return d + " dni";
  return new Date(iso).toLocaleDateString("pl-PL");
}

/* ────────── Auto-update of bank rates and FX ────────── */
function AdminAutoUpdate() {
  const [running, setRunning] = useStateA(false);
  const [log, setLog] = useStateA([
    { time: "2026-05-12 06:00:14", msg: "✅ Pobrano kursy NBP — 6 par zaktualizowanych", ok: true },
    { time: "2026-05-12 06:00:18", msg: "✅ EURIBOR / ECB — pobrano z api.ecb.europa.eu", ok: true },
    { time: "2026-05-12 06:00:25", msg: "✅ WIBOR 3M zaktualizowany do 5.86%", ok: true },
    { time: "2026-05-12 06:01:02", msg: "✅ Banki PL — 10 cenników odczytanych", ok: true },
    { time: "2026-05-12 06:01:38", msg: "✅ Banki EU — 96 cenników odczytanych", ok: true },
    { time: "2026-05-12 06:01:42", msg: "📬 Raport wysłany na kontakt@krediteu.com", ok: true },
  ]);
  const [schedule, setSchedule] = useStateA({
    enabled: true, frequency: "weekly", day: "monday", hour: "06:00",
    sources: { nbp: true, ecb: true, banks: true, ai_news: true },
  });

  const appendLog = (msg, ok = true) => {
    const now = new Date().toLocaleTimeString("pl-PL");
    setLog(l => [{ time: now, msg, ok }, ...l]);
  };

  const runNow = async () => {
    setRunning(true);
    const steps = [
      "Lacze z api.nbp.pl...",
      "Lacze z ECB / Stooq...",
      "Sprawdzam stopy referencyjne...",
      "Przeliczam oprocentowanie bankow z aktualnych benchmarkow...",
    ];
    steps.forEach((step, idx) => {
      window.setTimeout(() => appendLog(step, true), idx * 180);
    });

    try {
      const data = await adminFetch("/refresh.php", { method: "POST", body: "{}" });
      const fx = data.results?.fx;
      const refs = data.results?.reference_rates;
      const banks = data.results?.bank_rates;
      appendLog(`OK: kursy walut ${fx?.ok ? "pobrane" : "sprawdzone"} (${fx?.elapsed ?? 0}s)`, !!fx?.ok);
      appendLog(`OK: stopy referencyjne ${refs?.ok ? "pobrane" : "sprawdzone"} (${refs?.elapsed ?? 0}s)`, !!refs?.ok);
      appendLog(`OK: przeliczono ${banks?.updated ?? 0} stawek bankowych`, true);
      appendLog("Aktualizacja zakonczona. Odswiez ranking bankow, aby zobaczyc nowe wartosci.", true);
    } catch (err) {
      appendLog(`Blad aktualizacji: ${err.message || "nieznany blad"}`, false);
    } finally {
      setRunning(false);
    }
  };

  const next = useMemoA(() => {
    const now = new Date();
    const day = { monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6, sunday: 0 }[schedule.day];
    const next = new Date(now);
    let diff = (day - now.getDay() + 7) % 7 || 7;
    next.setDate(now.getDate() + diff);
    const [h, m] = schedule.hour.split(":");
    next.setHours(+h, +m, 0, 0);
    return next.toLocaleString("pl-PL", { dateStyle: "medium", timeStyle: "short" });
  }, [schedule]);

  return (
    <div>
      <SectionHeader title="🔄 Auto-aktualizacja danych"
        desc="Harmonogram tygodniowy: kursy walut, stopy bazowe, cenniki banków. Bez ręcznego klikania."
        action={
          <button className="btn btn-primary" onClick={runNow} disabled={running}>
            {running ? "⏳ Aktualizuję…" : "⚡ Uruchom teraz"}
          </button>
        }
      />

      {/* Schedule card */}
      <div className="card" style={{ padding: 24, marginBottom: 20, background: "linear-gradient(155deg, var(--accent-soft), transparent 60%), var(--surface)", border: "1px solid var(--accent)" }}>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 20, alignItems: "center" }}>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--accent)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 6 }}>
              Status
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
              <span className="live-dot" style={{ background: schedule.enabled ? "var(--good)" : "var(--text-3)" }} />
              <span style={{ fontSize: 18, fontWeight: 800 }}>{schedule.enabled ? "Aktywny" : "Wstrzymany"}</span>
            </div>
          </div>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--text-3)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 6 }}>
              Ostatnia aktualizacja
            </div>
            <div className="num-mono" style={{ fontSize: 18, fontWeight: 800 }}>12.05.2026 06:00</div>
          </div>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--text-3)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 6 }}>
              Następna aktualizacja
            </div>
            <div className="num-mono" style={{ fontSize: 18, fontWeight: 800, color: "var(--accent)" }}>{next}</div>
          </div>
          <div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--text-3)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 6 }}>
              Częstotliwość
            </div>
            <div style={{ fontSize: 18, fontWeight: 800 }}>1× w tygodniu</div>
          </div>
        </div>
      </div>

      {/* Settings */}
      <div className="card" style={{ padding: 24, marginBottom: 20 }}>
        <h4 style={subHead()}>⚙️ Harmonogram</h4>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 14 }}>
          <Field label="Status">
            <button onClick={() => setSchedule({ ...schedule, enabled: !schedule.enabled })}
              style={{
                width: "100%", padding: "12px 14px", textAlign: "left",
                background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10,
                color: "var(--text)", fontWeight: 700, cursor: "pointer",
                display: "flex", justifyContent: "space-between", alignItems: "center",
              }}>
              {schedule.enabled ? "✅ Włączony" : "⏸️ Wstrzymany"}
            </button>
          </Field>
          <Field label="Częstotliwość">
            <select className="select" value={schedule.frequency} onChange={e => setSchedule({ ...schedule, frequency: e.target.value })}>
              <option value="daily">Codziennie</option>
              <option value="weekly">Co tydzień (zalecane)</option>
              <option value="biweekly">Co 2 tygodnie</option>
              <option value="monthly">Co miesiąc</option>
            </select>
          </Field>
          <Field label="Dzień tygodnia">
            <select className="select" value={schedule.day} onChange={e => setSchedule({ ...schedule, day: e.target.value })}>
              <option value="monday">Poniedziałek</option>
              <option value="tuesday">Wtorek</option>
              <option value="wednesday">Środa</option>
              <option value="thursday">Czwartek</option>
              <option value="friday">Piątek</option>
              <option value="saturday">Sobota</option>
              <option value="sunday">Niedziela</option>
            </select>
          </Field>
          <Field label="Godzina">
            <input type="time" className="input" value={schedule.hour} onChange={e => setSchedule({ ...schedule, hour: e.target.value })} style={{ fontFamily: "var(--font-mono)" }} />
          </Field>
        </div>

        <h4 style={{ ...subHead(), marginTop: 24 }}>📡 Źródła danych</h4>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))", gap: 10 }}>
          {[
            ["nbp", "Kursy NBP", "api.nbp.pl/api/exchangerates"],
            ["ecb", "ECB Data", "data.ecb.europa.eu/api"],
            ["banks", "Cenniki banków", "scraper (10 PL + 96 EU)"],
            ["ai_news", "AI podsumowanie", "Claude / Gemini"],
          ].map(([k, name, src]) => (
            <label key={k} style={{
              display: "flex", alignItems: "center", gap: 10, padding: 12,
              background: "var(--bg-2)", borderRadius: 10, cursor: "pointer",
              border: "1px solid var(--border-soft)",
            }}>
              <input type="checkbox" checked={schedule.sources[k]}
                onChange={e => setSchedule({ ...schedule, sources: { ...schedule.sources, [k]: e.target.checked } })} />
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 700 }}>{name}</div>
                <div style={{ fontSize: 11, color: "var(--text-3)", fontFamily: "var(--font-mono)" }}>{src}</div>
              </div>
            </label>
          ))}
        </div>
      </div>

      {/* Log */}
      <div className="card" style={{ padding: 24, marginBottom: 20 }}>
        <h4 style={subHead()}>📜 Log aktualizacji</h4>
        <div style={{ maxHeight: 300, overflowY: "auto", fontFamily: "var(--font-mono)", fontSize: 12, background: "var(--bg-2)", borderRadius: 10, padding: 16 }}>
          {log.map((l, i) => (
            <div key={i} style={{ padding: "4px 0", display: "flex", gap: 12, color: l.ok ? "var(--text-2)" : "var(--bad)" }}>
              <span style={{ color: "var(--text-3)", flexShrink: 0 }}>{l.time}</span>
              <span>{l.msg}</span>
            </div>
          ))}
        </div>
      </div>

      {/* Tech setup */}
      <div className="card" style={{ padding: 24 }}>
        <h4 style={subHead()}>🛠️ Jak to działa technicznie</h4>
        <p style={{ marginTop: 0, fontSize: 13, color: "var(--text-2)", lineHeight: 1.6 }}>
          W produkcji harmonogram realizuje cron job, który uruchamia skrypt aktualizacyjny w wybrane dni i godziny. Skrypt pobiera dane z API NBP/ECB i parsuje cenniki banków, a następnie zapisuje do bazy.
        </p>
        <pre style={{
          marginTop: 12, padding: 16,
          background: "var(--bg-2)", borderRadius: 10,
          fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--text-2)",
          overflow: "auto",
        }}>{`# /etc/cron.d/krediteu
# Co poniedziałek o 06:00 — aktualizacja wszystkiego
0 6 * * 1   www-data  /usr/local/bin/krediteu-update.sh

# /usr/local/bin/krediteu-update.sh
#!/bin/bash
node /var/www/krediteu/scripts/fetch-nbp.js
node /var/www/krediteu/scripts/fetch-ecb.js
node /var/www/krediteu/scripts/scrape-banks.js
node /var/www/krediteu/scripts/ai-summary.js
curl -X POST https://krediteu.com/api/admin/refresh \\
     -H "X-API-Key: $KREDIT_API_KEY"`}</pre>
      </div>
    </div>
  );
}
function AdminArticles({ navigate }) {
  const emptyForm = { id: null, title: "", cat: "Kredyt hipoteczny", desc: "", body: "", img: "", imgAlt: "", aiPrompt: "" };
  const [form, setForm] = useStateA(emptyForm);
  const [list, setList] = useStateA(() => readStoredArticles());
  const [aiGen, setAiGen] = useStateA(false);
  const [preview, setPreview] = useStateA(false);
  const [notice, setNotice] = useStateA("");
  const fileRef = useRefA(null);

  useEffectA(() => {
    const loadDraft = () => {
      const raw = localStorage.getItem("kr_admin_article_draft");
      if (!raw) return;
      try {
        const draft = JSON.parse(raw);
        setForm(f => ({ ...f, ...draft, id: null }));
        setPreview(true);
        setNotice("Wczytano artykul z generatora AI. Sprawdz tresc, dodaj zdjecie i opublikuj.");
        localStorage.removeItem("kr_admin_article_draft");
      } catch (err) {
        setNotice("Nie udalo sie wczytac szkicu z generatora AI.");
      }
    };
    loadDraft();
    window.addEventListener("kr-admin-article-draft", loadDraft);
    return () => window.removeEventListener("kr-admin-article-draft", loadDraft);
  }, []);

  function persist(next) {
    setList(next);
    localStorage.setItem("kr_admin_articles", JSON.stringify(next));
    window.ARTICLES = mergeArticleLists(next, window.ARTICLES || []);
  }

  const publish = () => {
    if (!form.title.trim()) {
      setNotice("Dodaj tytul artykulu przed publikacja.");
      return;
    }
    const existing = list.find(a => a.id === form.id);
    const article = buildArticle(form, existing?.id || nextArticleId(list));
    const next = existing ? list.map(a => a.id === article.id ? article : a) : [article, ...list];
    persist(next);
    setForm(emptyForm);
    setPreview(false);
    setNotice("Artykul opublikowany. Otwieram podglad na stronie.");
    navigate?.({ name: "article", id: article.id });
  };

  const editArticle = (article) => {
    setForm({
      id: article.id,
      title: article.title || "",
      cat: article.cat || article.tag || "Kredyt hipoteczny",
      desc: article.excerpt || "",
      body: article.body || "",
      img: article.img || "",
      imgAlt: article.imgAlt || "",
      aiPrompt: article.aiPrompt || "",
    });
    setPreview(true);
    setNotice("Tryb edycji: po poprawkach kliknij Opublikuj zmiany.");
  };

  const removeArticle = (article) => {
    if (!article.custom) {
      setNotice("Artykuly systemowe nie sa usuwane z panelu lokalnego. Mozesz edytowac tylko nowe wpisy.");
      return;
    }
    persist(list.filter(x => x.id !== article.id));
  };

  const generateAiImage = () => {
    setAiGen(true);
    window.setTimeout(() => {
      setAiGen(false);
      setForm(f => ({ ...f, img: randomGradient(f.aiPrompt || f.title || "kredyt") }));
    }, 700);
  };

  const randomStock = () => {
    const id = Math.floor(Math.random() * 1000);
    setForm(f => ({ ...f, img: "center/cover url(https://picsum.photos/seed/krediteu-" + id + "/1200/720)" }));
  };

  const handleUpload = (e) => {
    const file = e.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (ev) => setForm(f => ({ ...f, img: "center/cover url(" + ev.target.result + ")" }));
    reader.readAsDataURL(file);
  };

  return (
    <div>
      <SectionHeader title="Artykuly - CMS"
        desc="Edytor z podgladem, uploadem zdjec i publikacja bez martwych przyciskow" />

      {notice && (
        <div className="card" style={{ padding: 14, marginBottom: 16, border: "1px solid var(--accent)", background: "var(--accent-soft)", fontSize: 13, color: "var(--text-2)" }}>
          {notice}
        </div>
      )}

      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr) minmax(320px, 0.8fr)", gap: 16, marginBottom: 24 }} className="kr-admin-grid">
        <div className="card" style={{ padding: 20 }}>
          <h4 style={subHead()}>{form.id ? "Edytuj artykul" : "Nowy artykul"}</h4>

          <Field label="Tytul artykulu">
            <input className="input" value={form.title} onChange={e => setForm({ ...form, title: e.target.value })} placeholder="np. Jak obnizyc rate kredytu w 2026 r." />
          </Field>
          <div style={{ height: 12 }} />
          <Field label="Kategoria">
            <select className="select" value={form.cat} onChange={e => setForm({ ...form, cat: e.target.value })}>
              <option>Kredyt hipoteczny</option>
              <option>Kredyt gotowkowy</option>
              <option>Programy rzadowe</option>
              <option>Finanse osobiste</option>
              <option>BIK i Scoring</option>
              <option>Kredyt w EUR</option>
            </select>
          </Field>
          <div style={{ height: 12 }} />
          <Field label="Opis SEO (max 160 znakow)" suffix={(form.desc.length) + " / 160"}>
            <textarea className="input" maxLength={160} rows={2} value={form.desc} onChange={e => setForm({ ...form, desc: e.target.value })}
              style={{ resize: "vertical" }} />
          </Field>
          <div style={{ height: 16 }} />

          <Field label="Zdjecie glowne">
            <div style={{
              width: "100%", aspectRatio: "16/9",
              background: form.img || "repeating-linear-gradient(135deg, var(--bg-2) 0 10px, var(--surface-2) 10px 20px)",
              borderRadius: 10,
              border: "1px solid var(--border-soft)",
              position: "relative",
              backgroundSize: form.img && form.img.includes("url(") ? "cover" : "auto",
              backgroundPosition: "center",
              overflow: "hidden",
              marginBottom: 10,
            }}>
              {aiGen && (
                <div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 12, background: "rgba(0,0,0,0.6)", backdropFilter: "blur(8px)" }}>
                  <div className="live-dot" style={{ width: 14, height: 14, background: "var(--accent)" }} />
                  <div style={{ color: "white", fontSize: 13, fontWeight: 700 }}>Generuje grafike...</div>
                </div>
              )}
              {!form.img && !aiGen && (
                <div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-3)", fontSize: 13, fontWeight: 600 }}>
                  Bez zdjecia - wybierz zrodlo ponizej
                </div>
              )}
            </div>

            <input type="text" className="input" placeholder="lub wklej URL zdjecia (https://...)"
              value={form.img && form.img.startsWith("center/cover") ? form.img.replace(/^center\/cover url\(/, "").replace(/\)$/, "") : ""}
              onChange={e => {
                const v = e.target.value;
                setForm(f => ({ ...f, img: v ? "center/cover url(" + v + ")" : "" }));
              }}
              style={{ marginBottom: 10, fontSize: 12 }} />

            <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
              <button className="btn btn-primary" onClick={generateAiImage} disabled={aiGen} style={{ fontSize: 11, padding: "8px 12px" }}>
                {aiGen ? "Generuje..." : "Generuj grafike"}
              </button>
              <button className="btn btn-soft" onClick={randomStock} style={{ fontSize: 11, padding: "8px 12px" }}>
                Losowe zdjecie
              </button>
              <button className="btn btn-soft" onClick={() => fileRef.current?.click()} style={{ fontSize: 11, padding: "8px 12px" }}>
                Upload
              </button>
              {form.img && (
                <button className="btn btn-soft" onClick={() => setForm(f => ({ ...f, img: "" }))} style={{ fontSize: 11, padding: "8px 12px", color: "var(--bad)" }}>
                  Usun
                </button>
              )}
              <input ref={fileRef} type="file" accept="image/*" onChange={handleUpload} style={{ display: "none" }} />
            </div>

            <input className="input" placeholder="Prompt dla grafiki (opcjonalnie)"
              value={form.aiPrompt} onChange={e => setForm(f => ({ ...f, aiPrompt: e.target.value }))}
              style={{ marginTop: 8, fontSize: 12 }} />
          </Field>

          <div style={{ height: 16 }} />
          <Field label="Tresc artykulu (Markdown)">
            <textarea className="input" rows={12} value={form.body} onChange={e => setForm({ ...form, body: e.target.value })}
              placeholder={"## Naglowek\nAkapit tekstu...\n\n- Punkt listy"}
              style={{ resize: "vertical", fontFamily: "var(--font-mono)", fontSize: 12 }} />
          </Field>
          <div style={{ marginTop: 16, display: "flex", flexWrap: "wrap", gap: 8 }}>
            <button className="btn btn-primary" onClick={publish}>{form.id ? "Opublikuj zmiany" : "Opublikuj"}</button>
            <button className="btn btn-soft" onClick={() => setPreview(p => !p)}>{preview ? "Ukryj podglad" : "Podglad"}</button>
            <button className="btn btn-soft" onClick={() => { setForm(emptyForm); setPreview(false); }}>Wyczysc</button>
          </div>
        </div>

        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          {preview && (
            <div className="card" style={{ padding: 20 }}>
              <h4 style={subHead()}>Podglad przed publikacja</h4>
              <div style={{ width: "100%", aspectRatio: "16/9", background: form.img || randomGradient(form.title), borderRadius: 10, marginBottom: 12, backgroundSize: "cover", backgroundPosition: "center" }} />
              <span className="chip" style={{ marginBottom: 10 }}>{form.cat}</span>
              <h3 style={{ margin: "8px 0", fontSize: 20, fontWeight: 800 }}>{form.title || "Tytul artykulu"}</h3>
              <p style={{ color: "var(--text-2)", lineHeight: 1.6 }}>{form.desc || "Opis SEO i wstep artykulu."}</p>
              <div style={{ fontSize: 13, lineHeight: 1.6, color: "var(--text-2)", maxHeight: 260, overflowY: "auto" }}>
                {renderArticleMarkdown(form.body || "Tresc artykulu pojawi sie tutaj.")}
              </div>
            </div>
          )}

          <div className="card" style={{ padding: 20 }}>
            <h4 style={subHead()}>Lista artykulow</h4>
            <div style={{ display: "flex", flexDirection: "column", gap: 8, maxHeight: 640, overflowY: "auto" }}>
              {list.map(a => (
                <div key={a.id} style={{
                  display: "grid",
                  gridTemplateColumns: "48px minmax(0, 1fr) auto auto auto",
                  gap: 10, alignItems: "center",
                  padding: 10,
                  background: "var(--bg-2)",
                  borderRadius: 10,
                }}>
                  <div style={{ width: 48, height: 32, background: a.img, borderRadius: 6, backgroundSize: "cover", backgroundPosition: "center" }} />
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontSize: 12, fontWeight: 700, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{a.title}</div>
                    <div style={{ fontSize: 10, color: "var(--text-3)" }}>{a.cat} - {a.date}</div>
                  </div>
                  <button title="Edytuj" style={iconBtn2()} onClick={() => editArticle(a)}>Ed</button>
                  <button title="Podglad" style={iconBtn2()} onClick={() => navigate?.({ name: "article", id: a.id })}>PV</button>
                  <button title="Usun" style={{ ...iconBtn2(), color: "var(--bad)" }} onClick={() => removeArticle(a)}>Del</button>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function readStoredArticles() {
  const base = window.ARTICLES || [];
  try {
    const custom = JSON.parse(localStorage.getItem("kr_admin_articles") || "[]");
    return mergeArticleLists(Array.isArray(custom) ? custom : [], base);
  } catch (err) {
    return base;
  }
}

function mergeArticleLists(custom, base) {
  const customIds = new Set(custom.map(a => a.id));
  return [...custom, ...base.filter(a => !customIds.has(a.id))];
}

function nextArticleId(list) {
  const max = list.reduce((m, a) => Math.max(m, Number(a.id) || 0), 0);
  return Math.max(1000, max + 1);
}

function slugifyArticle(title, id) {
  return (title || "artykul-" + id)
    .toLowerCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-|-$/g, "")
    .slice(0, 64) || ("artykul-" + id);
}

function buildArticle(form, id) {
  const body = (form.body || "").trim();
  return {
    id,
    custom: true,
    slug: slugifyArticle(form.title, id),
    title: form.title.trim(),
    cat: form.cat || "Finanse osobiste",
    excerpt: form.desc || body.slice(0, 155),
    body,
    date: new Date().toISOString().slice(0, 10),
    read: Math.max(3, Math.round((body.split(/\s+/).filter(Boolean).length || 500) / 220)),
    author: "Redakcja KreditEU",
    img: form.img || randomGradient(form.title),
    imgAlt: form.imgAlt || form.title,
    tag: form.cat || "Finanse osobiste",
    aiPrompt: form.aiPrompt || "",
  };
}

function renderArticleMarkdown(markdown) {
  const blocks = String(markdown || "").split(/\n{2,}/).filter(Boolean);
  return blocks.map((block, idx) => {
    const trimmed = block.trim();
    if (trimmed.startsWith("## ")) return <h3 key={idx} style={{ margin: "14px 0 8px", fontSize: 16, fontWeight: 800 }}>{trimmed.slice(3)}</h3>;
    if (trimmed.startsWith("- ")) {
      return <ul key={idx} style={{ margin: "8px 0 12px", paddingLeft: 20 }}>{trimmed.split(/\n/).map((line, i) => <li key={i}>{line.replace(/^-\s*/, "")}</li>)}</ul>;
    }
    return <p key={idx} style={{ margin: "0 0 10px" }}>{trimmed}</p>;
  });
}
function randomGradient(seed) {
  const s = (seed || "x").length;
  const palettes = [
    ["oklch(0.55 0.18 248)", "oklch(0.40 0.20 270)"],
    ["oklch(0.72 0.14 80)", "oklch(0.55 0.18 60)"],
    ["oklch(0.65 0.15 155)", "oklch(0.45 0.18 175)"],
    ["oklch(0.65 0.18 25)", "oklch(0.45 0.20 350)"],
  ];
  const p = palettes[s % palettes.length];
  return `linear-gradient(135deg, ${p[0]}, ${p[1]})`;
}

function chipBtn3() {
  return {
    padding: "4px 10px", background: "var(--surface)", border: "1px solid var(--border-soft)",
    borderRadius: 6, color: "var(--text-2)", fontSize: 11, fontWeight: 700, cursor: "pointer",
  };
}

/* ────────── AI Generator ────────── */
function AdminAI({ openArticles }) {
  const [provider, setProvider] = useStateA("claude");
  const [topic, setTopic] = useStateA("");
  const [gen, setGen] = useStateA(false);
  const [out, setOut] = useStateA(null);
  const generate = () => {
    if (!topic.trim()) return;
    setGen(true);
    setTimeout(() => {
      setGen(false);
      setOut({
        title: topic.split(" ").slice(0, 8).join(" "),
        excerpt: "Artykul SEO-friendly z FAQ i CTA do kalkulatora, wygenerowany przez " + (provider === "claude" ? "Claude" : "Gemini") + ".",
        body: [
          "## Wprowadzenie",
          "Ten szkic wymaga redakcyjnej weryfikacji, ale zawiera gotowa strukture artykulu finansowego dla KreditEU.",
          "",
          "## Najwazniejsze informacje",
          "- Wyjasnij aktualny kontekst stop procentowych i kosztu kredytu.",
          "- Pokaz, jak porownac oferty bankow w kalkulatorze.",
          "- Dodaj konkretne CTA do kontaktu albo porownywarki.",
          "",
          "## FAQ",
          "Czy warto refinansowac kredyt? To zalezy od marzy, prowizji i kosztow dodatkowych. Porownaj calkowity koszt przed decyzja.",
        ].join("\n"),
        cat: "Kredyt hipoteczny",
        words: 1200,
        time: provider === "claude" ? "$0.012" : "FREE",
      });
    }, 1800);
  };
  return (
    <div>
      <SectionHeader title="Generator artykułów AI" desc="Claude lub Gemini napisze artykuł finansowy z FAQ i CTA do kalkulatora" />
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }} className="kr-admin-grid">
        <div className="card" style={{ padding: 20 }}>
          <Field label="AI Provider">
            <div style={{ display: "flex", gap: 4, background: "var(--bg-2)", padding: 4, borderRadius: 10, border: "1px solid var(--border-soft)" }}>
              {[["claude", "🤖 Claude (Anthropic)"], ["gemini", "✨ Gemini (Google · FREE)"]].map(([k, l]) => (
                <button key={k} onClick={() => setProvider(k)} style={{
                  flex: 1, padding: "10px 12px",
                  background: provider === k ? "var(--surface)" : "transparent",
                  color: provider === k ? "var(--text)" : "var(--text-2)",
                  border: "none", borderRadius: 8, fontSize: 12, fontWeight: 700, cursor: "pointer",
                }}>{l}</button>
              ))}
            </div>
          </Field>
          <div style={{ height: 12 }} />
          <Field label="Temat artykułu">
            <input className="input" value={topic} onChange={e => setTopic(e.target.value)}
              placeholder="np. Jak obniżyć ratę kredytu hipotecznego w 2026 r." />
          </Field>
          <div style={{ height: 12 }} />
          <Field label="Kategoria">
            <select className="select">
              <option>AI wybierze automatycznie</option>
              <option>Kredyt hipoteczny</option>
              <option>Kredyt gotówkowy</option>
              <option>Programy rządowe</option>
            </select>
          </Field>
          <div style={{ height: 12 }} />
          <Field label="Długość">
            <select className="select">
              <option>Średni (800-1200 słów)</option>
              <option>Krótki (500 słów)</option>
              <option>Długi (2000+ słów)</option>
            </select>
          </Field>
          <button className="btn btn-primary" onClick={generate} disabled={gen} style={{ marginTop: 16, width: "100%", justifyContent: "center" }}>
            {gen ? "Generuję…" : "🤖 Generuj artykuł"}
          </button>
          <div style={{ marginTop: 12, fontSize: 11, color: "var(--text-3)" }}>
            <strong>Koszt:</strong> Claude Haiku ~$0.01/art. · Gemini Flash <strong style={{ color: "var(--good)" }}>DARMOWY</strong>
          </div>
        </div>

        <div className="card" style={{ padding: 20, minHeight: 300, display: "flex", flexDirection: "column" }}>
          {gen && (
            <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 12 }}>
              <div className="live-dot" style={{ width: 12, height: 12 }} />
              <span style={{ fontSize: 13, color: "var(--text-2)" }}>{provider === "claude" ? "Claude" : "Gemini"} pisze artykuł…</span>
              <div className="skeleton" style={{ width: "80%", height: 14 }} />
              <div className="skeleton" style={{ width: "90%", height: 14 }} />
              <div className="skeleton" style={{ width: "70%", height: 14 }} />
            </div>
          )}
          {!gen && !out && (
            <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", color: "var(--text-3)" }}>
              <div style={{ fontSize: 40, marginBottom: 12 }}>📝</div>
              <span style={{ fontSize: 13 }}>Wpisz temat i kliknij „Generuj artykuł"</span>
            </div>
          )}
          {out && (
            <div>
              <div style={{ fontSize: 11, fontWeight: 700, color: "var(--accent)", textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 8 }}>
                ✅ Wygenerowano · {out.words} słów · {out.time}
              </div>
              <h3 style={{ margin: 0, fontSize: 16, fontWeight: 800 }}>{out.title}…</h3>
              <p style={{ marginTop: 8, fontSize: 12, color: "var(--text-2)", lineHeight: 1.5 }}>{out.excerpt}</p>
              <div style={{ marginTop: 16, display: "flex", gap: 8 }}>
                <button className="btn btn-primary" onClick={() => {
                  localStorage.setItem("kr_admin_article_draft", JSON.stringify({
                    title: out.title,
                    desc: out.excerpt,
                    body: out.body,
                    cat: out.cat || "Kredyt hipoteczny",
                    aiPrompt: topic,
                  }));
                  window.dispatchEvent(new Event("kr-admin-article-draft"));
                  openArticles?.();
                }}>Otworz w edytorze</button>
                <button className="btn btn-soft" onClick={() => setOut(null)}>Odrzuc</button>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

/* ────────── Banks editor ────────── */
function AdminBanks() {
  const [list, setList] = useStateA(window.BANKS || []);
  const [centralRate, setCentralRate] = useStateA({ ECB: 2.40, NBP: 5.75, CNB: 4.00, MNB: 6.50 });
  const [status, setStatus] = useStateA("");
  const [loading, setLoading] = useStateA(false);
  const [saving, setSaving] = useStateA(false);

  const mapBackendBank = (row) => ({
    id: Number(row.id),
    name: row.name,
    country: row.country_code,
    mortgage: Number(row.mortgage_rate || 0),
    cash: Number(row.cash_rate || 0),
    rrso: Number(row.mortgage_rrso || row.cash_rrso || 0),
    cashRrso: Number(row.cash_rrso || 0),
    prov: Number(row.provision_pct || 0),
    trend: Number(row.trend || 0),
    active: Number(row.is_active ?? 1) === 1,
    website: row.website || "",
  });

  const refreshFromBackend = async () => {
    setLoading(true);
    setStatus("Pobieram banki z bazy...");
    try {
      const data = await adminFetch("/banks.php");
      const rows = (data.banks || []).map(mapBackendBank);
      setList(rows);
      window.BANKS = rows;
      setStatus("Pobrano " + rows.length + " bankow z bazy.");
    } catch (err) {
      setStatus("Nie udalo sie pobrac bankow z bazy: " + (err.message || "blad"));
    } finally {
      setLoading(false);
    }
  };

  useEffectA(() => {
    refreshFromBackend();
  }, []);

  const update = (id, field, val) => setList(list.map(b => b.id === id ? { ...b, [field]: parseFloat(val) || 0 } : b));

  const recalcAll = async () => {
    setSaving(true);
    setStatus("Uruchamiam aktualizacje stawek i benchmarkow...");
    try {
      const data = await adminFetch("/refresh.php", { method: "POST", body: "{}" });
      const updated = data.results?.bank_rates?.updated ?? 0;
      setStatus("Przeliczono " + updated + " stawek. Odswiezam tabele bankow...");
      await refreshFromBackend();
    } catch (err) {
      setStatus("Blad przeliczania: " + (err.message || "nieznany blad"));
    } finally {
      setSaving(false);
    }
  };

  const saveVisible = async () => {
    setSaving(true);
    setStatus("Zapisuje widoczne zmiany w bazie...");
    try {
      for (const bank of list) {
        await adminFetch("/banks.php", {
          method: "PUT",
          body: JSON.stringify({
            id: bank.id,
            mortgage_rate: bank.mortgage,
            cash_rate: bank.cash,
            mortgage_rrso: bank.rrso,
            cash_rrso: bank.cashRrso || bank.rrso,
            provision_pct: bank.prov,
            trend: bank.trend || 0,
          }),
        });
      }
      setStatus("Zmiany zapisane. Historia oprocentowania zostala dopisana w bazie.");
      await refreshFromBackend();
    } catch (err) {
      setStatus("Blad zapisu: " + (err.message || "nieznany blad"));
    } finally {
      setSaving(false);
    }
  };

  return (
    <div>
      <SectionHeader title="Oprocentowanie bankow"
        desc="Aktualizacja z bazy i przeliczenie stawek wedlug aktualnych benchmarkow"
      />

      {status && (
        <div className="card" style={{ padding: 14, marginBottom: 16, border: "1px solid var(--border-soft)", fontSize: 13, color: status.toLowerCase().includes("blad") ? "var(--bad)" : "var(--text-2)" }}>
          {status}
        </div>
      )}

      <div className="card" style={{ padding: 20, marginBottom: 20 }}>
        <h4 style={subHead()}>Stopy bankow centralnych</h4>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))", gap: 12 }}>
          {Object.entries(centralRate).map(([k, v]) => (
            <Field key={k} label={k}>
              <input className="input" type="number" step="0.05" value={v}
                onChange={e => setCentralRate({ ...centralRate, [k]: parseFloat(e.target.value) || 0 })}
                style={{ fontFamily: "var(--font-mono)", fontWeight: 700 }} />
            </Field>
          ))}
        </div>
        <div style={{ marginTop: 16, display: "flex", flexWrap: "wrap", gap: 8 }}>
          <button className="btn btn-soft" onClick={refreshFromBackend} disabled={loading || saving}>Pobierz z bazy</button>
          <button className="btn btn-primary" onClick={recalcAll} disabled={loading || saving}>{saving ? "Przeliczam..." : "Przelicz wszystkie"}</button>
          <button className="btn btn-soft" onClick={saveVisible} disabled={loading || saving}>Zapisz reczne zmiany</button>
        </div>
      </div>

      <SectionHeader title="Oprocentowanie indywidualne" desc="Edytuj stawki recznie dla kazdego banku albo przelicz je automatycznie" />
      <div className="card" style={{ padding: 0, overflow: "hidden" }}>
        <div style={{ maxHeight: 500, overflowY: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse" }}>
            <thead style={{ position: "sticky", top: 0, background: "var(--bg-2)" }}>
              <tr>
                <th style={th("left")}>Bank</th>
                <th style={th()}>Kraj</th>
                <th style={th()}>Hipot.</th>
                <th style={th()}>Gotowk.</th>
                <th style={th()}>RRSO</th>
                <th style={th()}>Prowizja</th>
              </tr>
            </thead>
            <tbody>
              {list.map(b => {
                const c = window.COUNTRIES.find(c => c.code === b.country);
                return (
                  <tr key={b.id} style={{ borderTop: "1px solid var(--border-soft)", opacity: b.active === false ? 0.55 : 1 }}>
                    <td style={{ ...td("left"), fontWeight: 600 }}>{b.name}</td>
                    <td style={td()}>{c?.flag || b.country}</td>
                    <td style={td()}><input className="input" type="number" step="0.01" value={b.mortgage} onChange={e => update(b.id, "mortgage", e.target.value)} style={editCellStyle()} /></td>
                    <td style={td()}><input className="input" type="number" step="0.01" value={b.cash} onChange={e => update(b.id, "cash", e.target.value)} style={editCellStyle()} /></td>
                    <td style={td()}><input className="input" type="number" step="0.01" value={b.rrso} onChange={e => update(b.id, "rrso", e.target.value)} style={editCellStyle()} /></td>
                    <td style={td()}><input className="input" type="number" step="0.1" value={b.prov} onChange={e => update(b.id, "prov", e.target.value)} style={editCellStyle()} /></td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}
function editCellStyle() {
  return { padding: "6px 8px", fontSize: 12, fontFamily: "var(--font-mono)", textAlign: "center", width: 80 };
}

/* ────────── FX editor ────────── */
function AdminFX() {
  const [list, setList] = useStateA(window.FX);
  return (
    <div>
      <SectionHeader title="Kursy walut" desc="Pobierz z NBP / ECB albo edytuj ręcznie. Bez klucza API."
        action={<button className="btn btn-primary">🌐 Pobierz NBP + ECB</button>}
      />
      <div className="card" style={{ padding: 0, overflow: "hidden" }}>
        <table style={{ width: "100%", borderCollapse: "collapse" }}>
          <thead>
            <tr style={{ background: "var(--bg-2)" }}>
              <th style={th("left")}>Para</th>
              <th style={th()}>Kurs</th>
              <th style={th()}>24h zmiana</th>
              <th style={th()}>7d zmiana</th>
              <th style={th()}>Źródło</th>
            </tr>
          </thead>
          <tbody>
            {list.map((fx, i) => (
              <tr key={fx.pair} style={{ borderTop: "1px solid var(--border-soft)" }}>
                <td style={{ ...td("left"), fontWeight: 600 }}>{fx.pair}</td>
                <td style={td()}><input className="input" type="number" step="0.0001" value={fx.value}
                  onChange={e => { const n = [...list]; n[i] = { ...fx, value: parseFloat(e.target.value) || 0 }; setList(n); }}
                  style={editCellStyle()} /></td>
                <td style={td()}><input className="input" type="number" step="0.01" value={fx.d24}
                  onChange={e => { const n = [...list]; n[i] = { ...fx, d24: parseFloat(e.target.value) || 0 }; setList(n); }}
                  style={editCellStyle()} /></td>
                <td style={td()}><input className="input" type="number" step="0.01" value={fx.d7}
                  onChange={e => { const n = [...list]; n[i] = { ...fx, d7: parseFloat(e.target.value) || 0 }; setList(n); }}
                  style={editCellStyle()} /></td>
                <td style={td()}><span className="chip" style={{ fontSize: 10 }}>{fx.source}</span></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <div style={{ marginTop: 16 }}>
        <button className="btn btn-primary">💾 Zapisz kursy</button>
      </div>
    </div>
  );
}

/* ────────── Theme editor ────────── */
function AdminTheme({ tweaks, setTweak }) {
  return (
    <div>
      <SectionHeader title="Motyw i kolory" desc="Zmieniaj przez panel Tweaks (prawy dolny róg) lub tutaj" />
      <div className="card" style={{ padding: 24 }}>
        <Field label="Wariant wizualny">
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))", gap: 8 }}>
            {["aurora", "daylight", "bold"].map(th => (
              <button key={th} onClick={() => setTweak("theme", th)} style={{
                padding: 16, background: tweaks.theme === th ? "var(--accent-soft)" : "var(--bg-2)",
                border: "1px solid " + (tweaks.theme === th ? "var(--accent)" : "var(--border-soft)"),
                borderRadius: 12, cursor: "pointer", textAlign: "center",
              }}>
                <div style={{ fontSize: 22, marginBottom: 6 }}>
                  {th === "aurora" ? "✨" : th === "daylight" ? "☀️" : "🔥"}
                </div>
                <div style={{ fontSize: 13, fontWeight: 700, textTransform: "capitalize" }}>{th}</div>
              </button>
            ))}
          </div>
        </Field>
        <div style={{ height: 16 }} />
        <Field label="Tryb">
          <div style={{ display: "flex", gap: 4, background: "var(--bg-2)", padding: 4, borderRadius: 10, border: "1px solid var(--border-soft)" }}>
            {["light", "dark"].map(m => (
              <button key={m} onClick={() => setTweak("mode", m)} style={{
                flex: 1, padding: "10px 12px",
                background: tweaks.mode === m ? "var(--surface)" : "transparent",
                color: tweaks.mode === m ? "var(--text)" : "var(--text-2)",
                border: "none", borderRadius: 8, fontSize: 13, fontWeight: 700, cursor: "pointer",
              }}>{m === "light" ? "☀️ Jasny" : "🌙 Ciemny"}</button>
            ))}
          </div>
        </Field>
        <div style={{ height: 16 }} />
        <Field label="Układ kafelków na home">
          <div style={{ display: "flex", gap: 4, background: "var(--bg-2)", padding: 4, borderRadius: 10, border: "1px solid var(--border-soft)" }}>
            {[["bento", "Bento (asymetryczne)"], ["grid", "Siatka (równe)"]].map(([k, l]) => (
              <button key={k} onClick={() => setTweak("tileLayout", k)} style={{
                flex: 1, padding: "10px 12px",
                background: tweaks.tileLayout === k ? "var(--surface)" : "transparent",
                color: tweaks.tileLayout === k ? "var(--text)" : "var(--text-2)",
                border: "none", borderRadius: 8, fontSize: 13, fontWeight: 700, cursor: "pointer",
              }}>{l}</button>
            ))}
          </div>
        </Field>
      </div>
    </div>
  );
}

/* ────────── Ads slot editor ────────── */
function AdminAds() {
  const slots = [
    { id: "header", name: "Pasek pod hero", size: "leaderboard 728×90", enabled: true },
    { id: "in-grid", name: "Wewnątrz bento", size: "in-grid 300×250", enabled: true },
    { id: "sidebar", name: "Sidebar przy artykule", size: "300×600 sticky", enabled: true },
    { id: "footer", name: "Pasek przed stopką", size: "leaderboard 728×90", enabled: true },
    { id: "mobile-bottom", name: "Mobile dolny", size: "320×50", enabled: false },
  ];
  const [list, setList] = useStateA(slots);
  return (
    <div>
      <SectionHeader title="Sloty reklamowe AdSense" desc="Włącz/wyłącz sloty i ustaw rozmiary. Klient sklepu nie zobaczy więcej niż 4 reklamy/strona." />
      <div className="card" style={{ padding: 20, marginBottom: 16, background: "var(--accent-soft)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 12 }}>
          <div>
            <div style={{ fontSize: 13, fontWeight: 700 }}>📐 Reklamy są wpisane w design, nie krzyczą.</div>
            <div style={{ fontSize: 11, color: "var(--text-2)", marginTop: 4 }}>Wszystkie sloty są oznaczone „Reklama", mają nasze obramowanie i stylistykę.</div>
          </div>
          <span className="chip" style={{ fontSize: 11 }}>AdSense ca-pub-4474448761999805</span>
        </div>
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
        {list.map((s, i) => (
          <div key={s.id} style={{
            display: "grid",
            gridTemplateColumns: "1fr auto auto",
            gap: 12, alignItems: "center",
            padding: 16, background: "var(--surface)",
            border: "1px solid var(--border-soft)", borderRadius: 12,
          }}>
            <div>
              <div style={{ fontSize: 14, fontWeight: 700 }}>{s.name}</div>
              <div style={{ fontSize: 11, color: "var(--text-3)" }}>{s.size}</div>
            </div>
            <input className="input" placeholder="data-ad-slot" style={{ width: 160, fontSize: 11, fontFamily: "var(--font-mono)", padding: "8px 10px" }} />
            <button onClick={() => { const n = [...list]; n[i] = { ...s, enabled: !s.enabled }; setList(n); }}
              style={{
                width: 44, height: 24, background: s.enabled ? "var(--accent)" : "var(--surface-2)",
                border: "none", borderRadius: 999, cursor: "pointer", position: "relative",
                transition: "all 0.2s",
              }}>
              <span style={{
                position: "absolute", top: 2, left: s.enabled ? 22 : 2,
                width: 20, height: 20, borderRadius: "50%", background: "white",
                transition: "left 0.2s",
              }} />
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ────────── i18n ────────── */
function AdminI18n() {
  return (
    <div>
      <SectionHeader title="Języki i tłumaczenia" desc="Strona dostępna w 7 językach Europy" />
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 12 }}>
        {window.LANGS.map(l => (
          <div key={l.code} className="card" style={{ padding: 16 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 8 }}>
              <span style={{ fontSize: 24 }}>{l.flag}</span>
              <div>
                <div style={{ fontSize: 14, fontWeight: 700 }}>{l.name}</div>
                <div style={{ fontSize: 10, color: "var(--text-3)", textTransform: "uppercase", letterSpacing: "0.06em" }}>{l.code}</div>
              </div>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, color: "var(--text-3)", marginBottom: 6 }}>
              <span>Tłumaczenia</span>
              <span style={{ color: "var(--good)", fontWeight: 700 }}>✓ 100%</span>
            </div>
            <ProgressBar value={100} />
          </div>
        ))}
      </div>
      <p style={{ marginTop: 16, fontSize: 11, color: "var(--text-3)" }}>
        💡 Tłumaczenia obejmują nawigację, hero, kalkulator i stopkę. Artykuły są w języku polskim — możesz wygenerować wersje obcojęzyczne przez Generator AI.
      </p>
    </div>
  );
}

function AdminSettings() {
  const [pw, setPw] = useStateA({ current: "", next: "", confirm: "" });
  const [pwMsg, setPwMsg] = useStateA(null);
  const [pwBusy, setPwBusy] = useStateA(false);

  const changePassword = async (e) => {
    e.preventDefault();
    setPwMsg(null);
    if (!pw.current || !pw.next || !pw.confirm) {
      setPwMsg({ ok: false, text: "Wypelnij wszystkie pola." });
      return;
    }
    if (pw.next !== pw.confirm) {
      setPwMsg({ ok: false, text: "Nowe hasla nie sa takie same." });
      return;
    }
    if (!isStrongAdminPassword(pw.next)) {
      setPwMsg({ ok: false, text: "Nowe haslo musi miec min. 16 znakow, duza litere, mala litere, cyfre i znak specjalny." });
      return;
    }
    setPwBusy(true);
    try {
      await adminFetch("/password.php", {
        method: "POST",
        body: JSON.stringify({
          current_password: pw.current,
          new_password: pw.next,
          new_password_confirm: pw.confirm,
        }),
      });
      setPwMsg({ ok: true, text: "Haslo zmienione. Sesja zostala odswiezona." });
      setPw({ current: "", next: "", confirm: "" });
    } catch (err) {
      setPwMsg({ ok: false, text: err.message || "Nie udalo sie zmienic hasla." });
    } finally {
      setPwBusy(false);
    }
  };

  return (
    <div>
      <SectionHeader title="Ustawienia" desc="Haslo administratora, klucze API, integracje" />
      <div className="card" style={{ padding: 20, marginBottom: 16 }}>
        <h4 style={subHead()}>Zmiana hasla admina</h4>
        <form onSubmit={changePassword}>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }} className="kr-admin-grid">
            <Field label="Obecne haslo">
              <input type="password" className="input" value={pw.current} onChange={e => setPw({ ...pw, current: e.target.value })} autoComplete="current-password" />
            </Field>
            <Field label="Nowe haslo">
              <input type="password" className="input" value={pw.next} onChange={e => setPw({ ...pw, next: e.target.value })} autoComplete="new-password" />
            </Field>
            <Field label="Powtorz nowe haslo">
              <input type="password" className="input" value={pw.confirm} onChange={e => setPw({ ...pw, confirm: e.target.value })} autoComplete="new-password" />
            </Field>
          </div>
          {pwMsg && (
            <div style={{
              marginTop: 14, padding: "10px 14px",
              background: pwMsg.ok ? "color-mix(in oklch, var(--good) 14%, transparent)" : "color-mix(in oklch, var(--bad) 14%, transparent)",
              border: "1px solid " + (pwMsg.ok ? "var(--good)" : "var(--bad)"),
              color: pwMsg.ok ? "var(--good)" : "var(--bad)",
              borderRadius: 10, fontSize: 12, fontWeight: 650,
            }}>
              {pwMsg.text}
            </div>
          )}
          <button type="submit" className="btn btn-primary" disabled={pwBusy} style={{ marginTop: 16 }}>
            {pwBusy ? "Zmieniam..." : "Zmien haslo"}
          </button>
        </form>
        <p style={{ marginTop: 12, fontSize: 11, color: "var(--text-3)" }}>
          Haslo nie jest zapisywane w przegladarce. Backend zapisuje tylko bcrypt + pepper w MySQL.
        </p>
      </div>

      <div className="card" style={{ padding: 20, marginBottom: 16 }}>
        <h4 style={subHead()}>Klucze API</h4>
        <Field label="Claude API Key">
          <input className="input" type="password" placeholder="sk-ant-..." />
        </Field>
        <div style={{ height: 12 }} />
        <Field label="Gemini API Key (darmowy)">
          <input className="input" type="password" placeholder="AIza..." />
        </Field>
        <button className="btn btn-primary" style={{ marginTop: 16 }}>Zapisz klucze</button>
      </div>

      <div className="card" style={{ padding: 20 }}>
        <h4 style={subHead()}>Integracje</h4>
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {[
            ["Google Analytics", "G-XXXXX", true],
            ["Google AdSense", "ca-pub-4474448761999805", true],
            ["NBP API", "api.nbp.pl (bez klucza)", true],
            ["ECB Data", "ecb.europa.eu (bez klucza)", true],
          ].map(([n, v, on]) => (
            <div key={n} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 0", borderBottom: "1px solid var(--border-soft)" }}>
              <div>
                <div style={{ fontSize: 13, fontWeight: 700 }}>{n}</div>
                <div style={{ fontSize: 11, color: "var(--text-3)", fontFamily: "var(--font-mono)" }}>{v}</div>
              </div>
              <span className="chip" style={{ color: on ? "var(--good)" : "var(--text-3)" }}>{on ? "Polaczone" : "Wylaczone"}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function SectionHeader({ title, desc, action }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", flexWrap: "wrap", gap: 12, marginBottom: 20 }}>
      <div>
        <h2 style={{ margin: 0, fontSize: 20, fontWeight: 800, letterSpacing: "-0.015em" }}>{title}</h2>
        {desc && <p style={{ marginTop: 4, fontSize: 12, color: "var(--text-2)" }}>{desc}</p>}
      </div>
      {action}
    </div>
  );
}
function subHead() { return { margin: 0, marginBottom: 16, fontSize: 13, fontWeight: 800, letterSpacing: "-0.01em" }; }

Object.assign(window, { AdminPage });
