// ============================================================
// admin.jsx — panel administracyjny (za symulowanym Cloudflare Access)
// ============================================================

function AdminGate({ children }) {
  const [authed, setAuthed] = React.useState(() => sessionStorage.getItem("sb-admin") === "1");
  if (authed) return children;
  return (
    <div className="page" style={{ display: "grid", placeItems: "center", background: "var(--ink)" }}>
      <div className="card pad" style={{ width: 400, display: "flex", flexDirection: "column", gap: 14 }}>
        <div className="kicker">cloudflare access · symulacja</div>
        <h2 style={{ fontSize: 20 }}>Panel administracyjny</h2>
        <p className="small muted">Dostęp ograniczony do listy e-maili (role: admin / moderator). Zero własnego kodu auth — uwierzytelnia Cloudflare Access.</p>
        <button className="btn primary block" onClick={() => { sessionStorage.setItem("sb-admin", "1"); setAuthed(true); }}>
          Zaloguj jako sebastian@… (admin)
        </button>
        <Link to="/" className="btn quiet sm">← Wróć na stronę</Link>
      </div>
    </div>
  );
}

const ADMIN_MODULES = [
  ["dashboard", "Dashboard"], ["lokalizacje", "Lokalizacje"], ["moderacja", "Moderacja"],
  ["glosy", "Głosy"], ["leady", "Leady"], ["gminy", "Gminy"], ["audit", "Audit log"],
];

function PageAdmin({ sub }) {
  const mod = sub || "dashboard";
  const s = useStore();
  const pend = pendingLocations();
  return (
    <AdminGate>
      <div style={{ display: "flex", minHeight: "calc(100vh - var(--nav-h))" }}>
        <aside style={{ width: 210, flex: "none", background: "var(--surface)", borderRight: "1px solid var(--line)", padding: "18px 10px", display: "flex", flexDirection: "column", gap: 2 }}>
          <div className="kicker" style={{ padding: "0 12px 10px" }}>admin</div>
          {ADMIN_MODULES.map(([key, label]) => (
            <Link key={key} to={"/admin/" + key} className={"nav-link" + (mod === key ? " active" : "")} style={{ display: "flex", justifyContent: "space-between" }}>
              {label}
              {key === "moderacja" && pend.length > 0 && <span className="badge amber">{pend.length}</span>}
            </Link>
          ))}
          <div style={{ marginTop: "auto", padding: "10px 12px" }}>
            <button className="btn quiet sm" onClick={() => { Store.reset(); toast("Dane demo zresetowane"); }}>↺ Reset danych demo</button>
          </div>
        </aside>
        <main className="scroll-y" style={{ flex: 1, padding: "26px 30px", minWidth: 0 }}>
          {mod === "dashboard" && <AdminDashboard />}
          {mod === "lokalizacje" && <AdminLocations />}
          {mod === "moderacja" && <AdminModeration />}
          {mod === "glosy" && <AdminVotes />}
          {mod === "leady" && <AdminLeads />}
          {mod === "gminy" && <AdminCommunes />}
          {mod === "audit" && <AdminAudit />}
        </main>
      </div>
    </AdminGate>
  );
}

function AdminH({ title, sub }) {
  return (
    <div style={{ marginBottom: 22 }}>
      <h1 style={{ fontSize: 24 }}>{title}</h1>
      {sub && <p className="small muted" style={{ marginTop: 4 }}>{sub}</p>}
    </div>
  );
}

// ---------- Dashboard ----------
function seedSeries() {
  // deterministyczny przebieg 90 dni
  const out = []; let x = 3;
  for (let i = 0; i < 90; i++) { x = (x * 16807) % 2147483647; out.push(2 + (x % 9) + Math.floor(i / 12)); }
  return out;
}
function AdminDashboard() {
  useStore();
  const t = platformTotals();
  const series = React.useMemo(seedSeries, []);
  const max = Math.max(...series);
  const agg = communeAggregates();
  const top = publishedLocations().map((l) => ({ l, v: votesFor(l.id) })).sort((a, b) => b.v.total - a.v.total).slice(0, 10);
  return (
    <div>
      <AdminH title="Dashboard" sub="Stan platformy — dane symulowane (prototyp)" />
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 14, marginBottom: 22 }}>
        {[[fmt(t.total), "potwierdzonych głosów"], ["✓ " + fmt(t.verified), "zweryfikowanych (" + Math.round(100 * t.verified / Math.max(1, t.total)) + "%)"],
          [fmt(t.locations), "opublikowanych lokalizacji"], ["68%", "współczynnik potwierdzeń e-mail"], [fmt(Store.get().leads.length), "leadów B2G/B2B"]].map(([n, l], i) => (
          <div key={i} className="card pad" style={{ padding: 16 }}>
            <div className="stat-num" style={{ fontSize: 26 }}>{n}</div>
            <div className="small muted" style={{ marginTop: 2 }}>{l}</div>
          </div>
        ))}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0,3fr) minmax(0,2fr)", gap: 14 }}>
        <div className="card pad">
          <div className="kicker" style={{ fontSize: 10.5, marginBottom: 14 }}>głosy / dzień · ostatnie 90 dni</div>
          <div style={{ display: "flex", alignItems: "flex-end", gap: 1.5, height: 120 }}>
            {series.map((v, i) => (
              <div key={i} style={{ flex: 1, background: i > 82 ? "var(--accent)" : "var(--accent-soft)", height: (100 * v / max) + "%", borderRadius: "1px 1px 0 0" }} title={v + " głosów"}></div>
            ))}
          </div>
          <div className="small mono muted" style={{ display: "flex", justifyContent: "space-between", marginTop: 8, fontSize: 10.5 }}>
            <span>−90 dni</span><span>dziś</span>
          </div>
        </div>
        <div className="card pad">
          <div className="kicker" style={{ fontSize: 10.5, marginBottom: 12 }}>gminy · flaga „gorąca gmina" ≥ 50 głosów</div>
          <table className="table">
            <thead><tr><th>Gmina</th><th className="num">Głosy</th><th className="num">✓</th><th></th></tr></thead>
            <tbody>
              {agg.map((a) => (
                <tr key={a.commune}>
                  <td style={{ fontWeight: 600 }}>{a.commune}</td>
                  <td className="num">{fmt(a.total)}</td>
                  <td className="num" style={{ color: "var(--green)" }}>{fmt(a.verified)}</td>
                  <td>{a.total >= 50 && <span className="badge amber">🔥 oferta B2G</span>}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
      <div className="card pad" style={{ marginTop: 14 }}>
        <div className="kicker" style={{ fontSize: 10.5, marginBottom: 12 }}>top 10 lokalizacji</div>
        <table className="table">
          <thead><tr><th>#</th><th>Lokalizacja</th><th>Gmina</th><th>Źródło</th><th className="num">Głosy</th><th className="num">✓ zweryf.</th></tr></thead>
          <tbody>
            {top.map(({ l, v }, i) => (
              <tr key={l.id}>
                <td className="num mono">{i + 1}</td>
                <td><Link to={"/lokalizacja/" + l.slug} style={{ fontWeight: 600, textDecoration: "none" }}>{l.name}</Link></td>
                <td>{l.commune}</td>
                <td>{l.source === "admin" ? <span className="badge blue">koncepcja</span> : <span className="badge green">propozycja</span>}</td>
                <td className="num">{fmt(v.total)}</td>
                <td className="num" style={{ color: "var(--green)" }}>{fmt(v.verified)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ---------- Lokalizacje ----------
function AdminLocations() {
  const s = useStore();
  const [adding, setAdding] = React.useState(false);
  const [form, setForm] = React.useState({ name: "", lat: "", lng: "", ms: "", mp: "" });
  const locs = allLocations().filter((l) => l.status === "published");
  const archive = (id) => {
    Store.set({ archived: [...Store.get().archived, id] });
    Store.audit("admin", "archive", "location", { id });
    toast("Lokalizacja zarchiwizowana");
  };
  const add = () => {
    const lat = parseFloat(form.lat), lng = parseFloat(form.lng);
    if (!form.name.trim() || isNaN(lat) || isNaN(lng)) return toast("Uzupełnij nazwę i współrzędne");
    const id = "A" + Date.now();
    Store.set({ adminLocations: [...Store.get().adminLocations, {
      id, slug: slugify(form.name) + "-" + id.slice(-4), source: "admin", status: "published",
      name: form.name, commune: "Krosno", lat, lng, ms: parseInt(form.ms) || 0, mp: parseInt(form.mp) || 0,
      landCat: "parking", addressLabel: form.name + ", Krosno", desc: "Lokalizacja dodana z panelu administracyjnego.",
      createdAt: new Date().toISOString().slice(0, 10),
    }] });
    Store.audit("admin", "create", "location", { name: form.name });
    setAdding(false); setForm({ name: "", lat: "", lng: "", ms: "", mp: "" });
    toast("Lokalizacja opublikowana");
  };
  return (
    <div>
      <AdminH title="Lokalizacje" sub="CRUD lokalizacji koncepcyjnych — publikacja natychmiastowa (source=admin). Gmina przypisywana automatycznie (PostGIS / PRG)." />
      <div style={{ display: "flex", gap: 8, marginBottom: 16 }}>
        <button className="btn primary sm" onClick={() => setAdding(!adding)}>{adding ? "Anuluj" : "+ Dodaj lokalizację"}</button>
        <button className="btn ghost sm" onClick={() => toast("Import wsadowy GeoJSON/CSV — poza zakresem prototypu")}>⇪ Import GeoJSON/CSV</button>
      </div>
      {adding && (
        <div className="card pad" style={{ marginBottom: 16, display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr auto", gap: 10, alignItems: "end" }}>
          <div className="field"><label>Nazwa</label><input className="input" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} /></div>
          <div className="field"><label>Szer. (lat)</label><input className="input" placeholder="49.69" value={form.lat} onChange={(e) => setForm({ ...form, lat: e.target.value })} /></div>
          <div className="field"><label>Dł. (lng)</label><input className="input" placeholder="21.76" value={form.lng} onChange={(e) => setForm({ ...form, lng: e.target.value })} /></div>
          <div className="field"><label>MS</label><input className="input" value={form.ms} onChange={(e) => setForm({ ...form, ms: e.target.value })} /></div>
          <div className="field"><label>mp</label><input className="input" value={form.mp} onChange={(e) => setForm({ ...form, mp: e.target.value })} /></div>
          <button className="btn accent" onClick={add}>Publikuj</button>
        </div>
      )}
      <div className="card">
        <table className="table">
          <thead><tr><th>Lokalizacja</th><th>Gmina</th><th>Źródło</th><th className="num">MS</th><th className="num">mp</th><th className="num">Głosy</th><th></th></tr></thead>
          <tbody>
            {locs.map((l) => (
              <tr key={l.id}>
                <td><Link to={"/lokalizacja/" + l.slug} style={{ fontWeight: 600, textDecoration: "none" }}>{l.name}</Link></td>
                <td>{l.commune}</td>
                <td>{l.source === "admin" ? <span className="badge blue">admin</span> : <span className="badge green">user</span>}</td>
                <td className="num">{l.ms ? fmt(l.ms) : "—"}</td>
                <td className="num">{l.mp ? fmt(l.mp) : "—"}</td>
                <td className="num">{fmt(votesFor(l.id).total)}</td>
                <td><button className="btn quiet sm" onClick={() => archive(l.id)}>Archiwizuj</button></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ---------- Moderacja ----------
function AdminModeration() {
  useStore();
  const pend = pendingLocations();
  const [rejecting, setRejecting] = React.useState(null);
  const [reason, setReason] = React.useState("");
  const [merging, setMerging] = React.useState(null);
  const act = (id, action, extra) => {
    Store.set({ moderated: { ...Store.get().moderated, [id]: { action, ...extra } } });
    Store.audit("moderator", action, "location", { id, ...extra });
    toast(action === "approved" ? "Propozycja opublikowana" : action === "rejected" ? "Propozycja odrzucona — e-mail z powodem wysłany" : "Scalono — głosy przepięte z deduplikacją");
    setRejecting(null); setMerging(null); setReason("");
  };
  return (
    <div>
      <AdminH title="Kolejka moderacji" sub={"Propozycje pending: " + pend.length + " · SLA wewnętrzne: 48 h · automatyczna sugestia scalenia dla lokalizacji w promieniu 150 m"} />
      {pend.length === 0 && <div className="card pad small muted">Kolejka pusta — wszystkie propozycje rozpatrzone.</div>}
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        {pend.map((p) => {
          const near = nearbyLocations(p.lat, p.lng, 150, p.id).filter((n) => n.status === "published");
          return (
            <div key={p.id} className="card pad" style={{ display: "flex", flexDirection: "column", gap: 12 }}>
              <div style={{ display: "flex", justifyContent: "space-between", gap: 12, flexWrap: "wrap" }}>
                <div>
                  <b style={{ fontSize: 16 }}>{p.name}</b>
                  <div className="small muted">{p.addressLabel} · {LAND_CATS[p.landCat]} · zgłoszono {p.createdAt}</div>
                </div>
                <span className="badge amber">pending</span>
              </div>
              <p className="small" style={{ color: "var(--ink-2)", background: "var(--surface-2)", padding: "10px 14px", borderRadius: 4 }}>„{p.desc}"</p>
              <div className="small mono muted" style={{ fontSize: 11.5 }}>{p.lat.toFixed(5)}, {p.lng.toFixed(5)} · gmina: {p.commune} (przypisana serwerowo)</div>
              {near.length > 0 && (
                <div className="card" style={{ padding: "10px 14px", borderColor: "var(--amber)", background: "var(--amber-soft)", fontSize: 13 }}>
                  ⚠ <b>Możliwy duplikat:</b> {near.map((n) => `„${n.name}" (${Math.round(n.dist)} m)`).join(", ")} — rozważ scalenie.
                </div>
              )}
              {rejecting === p.id ? (
                <div style={{ display: "flex", gap: 8 }}>
                  <input className="input" placeholder="Powód odrzucenia (trafi e-mailem do zgłaszającego)" value={reason} onChange={(e) => setReason(e.target.value)} />
                  <button className="btn danger sm" disabled={!reason.trim()} onClick={() => act(p.id, "rejected", { reason })}>Odrzuć</button>
                  <button className="btn quiet sm" onClick={() => setRejecting(null)}>Anuluj</button>
                </div>
              ) : merging === p.id ? (
                <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
                  <span className="small" style={{ fontWeight: 600 }}>Scal z:</span>
                  {(near.length ? near : nearbyLocations(p.lat, p.lng, 3000, p.id)).slice(0, 3).map((n) => (
                    <button key={n.id} className="btn ghost sm" onClick={() => act(p.id, "merged", { target: n.id })}>„{n.name}" ({Math.round(n.dist)} m)</button>
                  ))}
                  <button className="btn quiet sm" onClick={() => setMerging(null)}>Anuluj</button>
                </div>
              ) : (
                <div style={{ display: "flex", gap: 8 }}>
                  <button className="btn green sm" onClick={() => act(p.id, "approved")}>✓ Zatwierdź i opublikuj</button>
                  <button className="btn ghost sm" onClick={() => setMerging(p.id)}>⇄ Scal z istniejącą</button>
                  <button className="btn quiet sm" onClick={() => setRejecting(p.id)}>✕ Odrzuć</button>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ---------- Głosy ----------
function AdminVotes() {
  useStore();
  const rows = publishedLocations().map((l) => ({ l, v: votesFor(l.id) })).sort((a, b) => b.v.total - a.v.total);
  const exportCsv = (full) => {
    if (full) {
      const cel = prompt("Eksport pełny zawiera adresy e-mail. Podaj cel eksportu (zostanie zapisany w audit logu):");
      if (!cel) return;
      Store.audit("admin", "export_full", "declarations", { cel });
      toast("Eksport pełny zarejestrowany w audit logu");
      return;
    }
    const lines = ["lokalizacja;gmina;glosy;kupno;najem;poparcie;zweryfikowane"];
    rows.forEach(({ l, v }) => lines.push([l.name, l.commune, v.total, v.buy, v.rent, v.support, v.verified].join(";")));
    const a = document.createElement("a");
    a.href = "data:text/csv;charset=utf-8," + encodeURIComponent(lines.join("\n"));
    a.download = "agregaty.csv"; a.click();
    Store.audit("admin", "export_aggregates", "declarations", null);
  };
  return (
    <div>
      <AdminH title="Głosy" sub="Wyłącznie agregaty — publiczne API nigdy nie zwraca rekordów jednostkowych. Widełki cen przy n ≥ 10." />
      <div style={{ display: "flex", gap: 8, marginBottom: 16 }}>
        <button className="btn ghost sm" onClick={() => exportCsv(false)}>⇩ Eksport agregatów (CSV)</button>
        <button className="btn ghost sm" onClick={() => exportCsv(true)}>⇩ Eksport pełny (wymaga celu → audit log)</button>
      </div>
      <div className="card">
        <table className="table">
          <thead><tr><th>Lokalizacja</th><th>Gmina</th><th className="num">Razem</th><th className="num">Kupno</th><th className="num">Najem</th><th className="num">Poparcie</th><th className="num">✓ zweryf.</th><th style={{ width: 160 }}>Rozkład</th></tr></thead>
          <tbody>
            {rows.map(({ l, v }) => (
              <tr key={l.id}>
                <td style={{ fontWeight: 600 }}>{l.name}</td>
                <td>{l.commune}</td>
                <td className="num"><b>{fmt(v.total)}</b></td>
                <td className="num">{v.buy}</td><td className="num">{v.rent}</td><td className="num">{v.support}</td>
                <td className="num" style={{ color: "var(--green)" }}>{v.verified}</td>
                <td>
                  {v.total > 0 && <div className="distbar" style={{ height: 6 }}>
                    <div className="buy" style={{ width: (100 * v.buy / v.total) + "%" }}></div>
                    <div className="rent" style={{ width: (100 * v.rent / v.total) + "%" }}></div>
                    <div className="support" style={{ width: (100 * v.support / v.total) + "%" }}></div>
                  </div>}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ---------- Leady ----------
function AdminLeads() {
  const s = useStore();
  const setStatus = (ts, status) => Store.set({ leads: s.leads.map((l) => l.ts === ts ? { ...l, status } : l) });
  return (
    <div>
      <AdminH title="Leady B2G / B2B" sub="Zgłoszenia z formularzy /gminy, /inwestorzy i /kontakt" />
      {s.leads.length === 0 && <div className="card pad small muted">Brak leadów. Wyślij formularz na stronie <Link to="/gminy" style={{ color: "var(--accent)" }}>/gminy</Link>, by zobaczyć go tutaj.</div>}
      {s.leads.length > 0 && (
        <div className="card">
          <table className="table">
            <thead><tr><th>Typ</th><th>Organizacja</th><th>Kontakt</th><th>E-mail</th><th>Strona</th><th>Status</th></tr></thead>
            <tbody>
              {s.leads.map((l) => (
                <tr key={l.ts}>
                  <td><span className={"badge " + (l.type === "gmina" ? "blue" : l.type === "inwestor" ? "green" : "")}>{l.type}</span></td>
                  <td style={{ fontWeight: 600 }}>{l.organization || "—"}</td>
                  <td>{l.contact || "—"}</td>
                  <td className="mono" style={{ fontSize: 12 }}>{l.email}</td>
                  <td className="mono" style={{ fontSize: 12 }}>{l.page}</td>
                  <td>
                    <select className="select" style={{ padding: "4px 8px", fontSize: 12.5, width: "auto" }} value={l.status} onChange={(e) => setStatus(l.ts, e.target.value)}>
                      <option value="new">nowy</option><option value="contact">kontakt</option>
                      <option value="offer">oferta</option><option value="won">wygrany</option><option value="lost">przegrany</option>
                    </select>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ---------- Gminy ----------
function AdminCommunes() {
  useStore();
  const agg = communeAggregates();
  return (
    <div>
      <AdminH title="Gminy" sub={"Aktywacja dedykowanych widoków /mapa/[gmina] i progi flagi „gorąca gmina”"} />
      <div className="card">
        <table className="table">
          <thead><tr><th>Gmina</th><th className="num">Lokalizacje</th><th className="num">Głosy</th><th className="num">✓</th><th>Próg 🔥</th><th>Widok dedykowany</th></tr></thead>
          <tbody>
            {agg.map((a) => (
              <tr key={a.commune}>
                <td style={{ fontWeight: 600 }}>{a.commune}</td>
                <td className="num">{a.locations}</td>
                <td className="num">{fmt(a.total)}</td>
                <td className="num" style={{ color: "var(--green)" }}>{fmt(a.verified)}</td>
                <td className="num mono">50</td>
                <td>{a.commune === "Krosno" ? <span className="badge green">aktywny</span> : <span className="badge">nieaktywny</span>}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ---------- Audit ----------
function AdminAudit() {
  const s = useStore();
  return (
    <div>
      <AdminH title="Audit log" sub="Akcje administracyjne, moderacja i eksporty — każdy eksport z danymi osobowymi wymaga podania celu" />
      {s.audit.length === 0 && <div className="card pad small muted">Brak wpisów — wykonaj akcję (głos, moderacja, eksport), by zobaczyć log.</div>}
      {s.audit.length > 0 && (
        <div className="card">
          <table className="table">
            <thead><tr><th>Czas</th><th>Aktor</th><th>Akcja</th><th>Obiekt</th><th>Meta</th></tr></thead>
            <tbody>
              {s.audit.map((a, i) => (
                <tr key={i}>
                  <td className="mono" style={{ fontSize: 12 }}>{new Date(a.ts).toLocaleString("pl-PL")}</td>
                  <td>{a.actor}</td>
                  <td><span className="badge">{a.action}</span></td>
                  <td>{a.entity}</td>
                  <td className="mono" style={{ fontSize: 11.5, color: "var(--ink-3)" }}>{a.meta ? JSON.stringify(a.meta) : "—"}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { PageAdmin });
