// Reports, Migration and the Audit Log.

const LAR_OFFENCE_LABELS = {
  unauthorized_kick: "Unauthorized kick", forced_teleport: "Forced teleport", unauthorized_rpc: "Unauthorized RPC",
  impossible_movement: "Impossible movement", spawn_flood: "Spawn flood", illegal_item: "Illegal item",
  staff_report: "Staff report", illegal_environment: "Tampered environment (self)", device_rooted: "Rooted device (self)",
};

function LarReportsPage() {
  const [accused, setAccused] = React.useState("");
  const [filter, setFilter] = React.useState("");
  const { data, error, loading, reload } = useLarLoad(() => larApi(filter ? `reports?accused=${encodeURIComponent(filter)}&limit=200` : "reports?limit=200"), [filter]);

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Reports</h1>
          <p className="page-subtitle">Cheat reports from games and staff. A case needs 3 different players in the same room within 15 minutes before it alerts Discord; reporters who name many players are flagged instead. Uncounted rows were ignored as duplicates or floods.</p>
        </div>
        <div className="page-head-actions"><button className="btn btn-sm" onClick={reload}>Refresh</button></div>
      </div>
      <div className="card card-flush">
        <form className="toolbar" onSubmit={e => { e.preventDefault(); setFilter(accused.trim()); }}>
          <div className="search-field" style={{maxWidth:360}}><Icon name="search" size={14}/><input placeholder="Filter by accused Player ID…" value={accused} onChange={e => setAccused(e.target.value)}/></div>
          <button className="btn btn-sm" type="submit">Filter</button>
          {filter && <button className="btn btn-sm btn-ghost" type="button" onClick={() => { setAccused(""); setFilter(""); }}>Clear</button>}
        </form>
        {error && <div className="tiny" style={{color:"var(--danger)", padding:"0 16px 12px"}}>{error}</div>}
        <table className="tbl">
          <thead><tr><th>Offence</th><th>Accused</th><th>Reporter</th><th>Room</th><th>Counted</th><th style={{textAlign:"right"}}>When</th></tr></thead>
          <tbody>
            {(data?.reports || []).map(r => (
              <tr key={r.id}>
                <td>{LAR_OFFENCE_LABELS[r.offence] || r.offence}{r.detail && <div className="tiny muted">{r.detail}</div>}</td>
                <td className="mono lar-row-click" onClick={() => window.larOpenPlayer(r.accused)}>{r.accused}</td>
                <td className="mono lar-row-click" onClick={() => window.larOpenPlayer(r.reporter)}>{r.reporter}</td>
                <td className="mono tiny">{r.room}</td>
                <td>{r.counted ? <span className="tag tag-success">Yes</span> : <span className="tag">No</span>}</td>
                <td className="tiny muted" style={{textAlign:"right"}}>{timeSince(larIso(r.at))}</td>
              </tr>
            ))}
            {data && !data.reports.length && <tr><td colSpan={6}><div className="empty"><h3>No reports</h3><p>Nothing reported{filter ? " for this player" : ""}.</p></div></td></tr>}
            {loading && <tr><td colSpan={6}><div className="empty"><h3>Loading…</h3></div></td></tr>}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function LarImportButton({ label, path, body, confirmText }) {
  const [busy, setBusy] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const run = async () => {
    if (!confirm(confirmText)) return;
    setBusy(true); setResult(null);
    try { setResult({ ok: true, data: await larApi(path, { method: "POST", body }) }); }
    catch (e) { setResult({ ok: false, error: e.message }); }
    setBusy(false);
  };
  return (
    <div style={{padding:"8px 0", borderBottom:"1px solid var(--border)"}}>
      <div className="spread"><span style={{fontSize:12.5}}>{label}</span><button className="btn btn-sm" disabled={busy} onClick={run}>{busy ? "Importing…" : "Import"}</button></div>
      {result?.ok && <div className="tiny mt-4" style={{color:"var(--success)"}}>Imported {fmt.num(result.data.imported)}{result.data.notPurchasable ? ` · ${result.data.notPurchasable.length} set to grant only` : ""}</div>}
      {result && !result.ok && <div className="tiny mt-4" style={{color:"var(--danger)"}}>{result.error === "playfab_not_configured" ? "The LAR API has no PLAYFAB_SECRET_KEY yet." : result.error}</div>}
    </div>
  );
}

function LarMigrationPage() {
  const status = useLarLoad(() => larApi("migration"), []);
  const issues = useLarLoad(() => larApi("migration/issues?limit=200"), []);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [batch, setBatch] = React.useState("25");
  const [concurrency, setConcurrency] = React.useState("5");
  const s = status.data;

  React.useEffect(() => {
    if (s?.status !== "running") return;
    const t = setInterval(() => { status.reload(); issues.reload(); }, 5000);
    return () => clearInterval(t);
  }, [s?.status]);

  const act = async (what, body) => {
    setBusy(true); setError(null);
    try { await larApi(`migration/${what}`, { method: "POST", body }); status.reload(); issues.reload(); }
    catch (e) { setError(e.message === "playfab_not_configured" ? "Add PLAYFAB_SECRET_KEY to the LAR API first (npx wrangler secret put PLAYFAB_SECRET_KEY in Tools/LarBackend)." : e.message); }
    setBusy(false);
  };

  const start = () => {
    if (!confirm("Copy every PlayFab player into the LAR API? It is read-only on PlayFab and can be paused.")) return;
    act("start", { batch: Number(batch), concurrency: Number(concurrency) });
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Migration</h1>
          <p className="page-subtitle">Moves players off PlayFab. Players are also copied the moment they first log in through the LAR API; this walks everyone else so PlayFab can be switched off. A copied player is refreshed from PlayFab once more on their first login, so nothing they do on an old build is lost.</p>
        </div>
      </div>

      <LarMigrationCard/>

      <div className="row row-1-1 section-gap">
        <div className="card card-pad">
          <div className="card-head"><div><div className="card-title">Bulk copy</div><div className="card-sub">walks PlayFab's "All Players" segment</div></div></div>
          <div className="lar-grid-form">
            <div className="field"><label>Players per step</label><input className="input mono" type="number" min="1" max="100" value={batch} onChange={e => setBatch(e.target.value)}/></div>
            <div className="field"><label>Parallel players</label><input className="input mono" type="number" min="1" max="20" value={concurrency} onChange={e => setConcurrency(e.target.value)}/></div>
          </div>
          <div className="h-stack gap-8 mt-12">
            {(!s || ["idle", "done", "failed"].includes(s.status)) && <button className="btn btn-sm btn-accent" disabled={busy} onClick={start}>{s?.status === "done" ? "Run again" : "Start"}</button>}
            {s?.status === "running" && <button className="btn btn-sm" disabled={busy} onClick={() => act("pause")}>Pause</button>}
            {(s?.status === "paused" || s?.status === "failed") && <button className="btn btn-sm" disabled={busy} onClick={() => act("resume")}>Resume</button>}
          </div>
          {s?.lastError && <div className="tiny mt-8" style={{color:"var(--danger)"}}>Last error: {s.lastError}</div>}
          <LarError error={error}/>
        </div>
        <div className="card card-pad">
          <div className="card-head"><div><div className="card-title">Catalog and title data</div><div className="card-sub">replace what is here with PlayFab's current copy</div></div></div>
          <LarImportButton label="Catalog: Main" path="import/catalog" body={{ catalog: "Main" }} confirmText="Replace the Main catalog with PlayFab's? 0-gold items become grant only."/>
          <LarImportButton label="Catalog: Items" path="import/catalog" body={{ catalog: "Items" }} confirmText="Replace the Items catalog with PlayFab's? 0-gold items become grant only."/>
          <LarImportButton label="Title data (QuestConfig and QuestWeeklyBonus stay server only)" path="import/title-data" body={{}} confirmText="Copy all of PlayFab's title data over the keys here?"/>
        </div>
      </div>

      <div className="card card-flush section-gap">
        <div className="toolbar"><strong style={{fontSize:13}}>Players not copied</strong><span className="tiny muted">No Meta login link means they could not log in through the auth server anyway.</span></div>
        <table className="tbl">
          <thead><tr><th>PlayFab ID</th><th>Reason</th><th>Detail</th><th style={{textAlign:"right"}}>When</th></tr></thead>
          <tbody>
            {(issues.data?.issues || []).map(i => (
              <tr key={i.playFabId}><td className="mono">{i.playFabId}</td><td><span className={`tag ${i.reason === "failed" ? "tag-danger" : "tag-warn"}`}>{i.reason}</span></td><td className="tiny muted">{i.detail}</td><td className="tiny muted" style={{textAlign:"right"}}>{timeSince(larIso(i.at))}</td></tr>
            ))}
            {issues.data && !issues.data.issues.length && <tr><td colSpan={4}><div className="empty"><h3>None</h3><p>Every player seen so far was copied.</p></div></td></tr>}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function LarAuditPage() {
  const [entries, setEntries] = React.useState([]);
  const [done, setDone] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [target, setTarget] = React.useState("");
  const [filter, setFilter] = React.useState("");

  const load = async (reset) => {
    setBusy(true); setError(null);
    try {
      const before = !reset && entries.length ? `&before=${entries[entries.length - 1].id}` : "";
      const t = filter ? `&target=${encodeURIComponent(filter)}` : "";
      const res = await larApi(`audit?limit=100${before}${t}`);
      setEntries(reset ? res.entries : [...entries, ...res.entries]);
      setDone(res.entries.length < 100);
    } catch (e) { setError(e.message); }
    setBusy(false);
  };
  React.useEffect(() => { load(true); }, [filter]);

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Audit Log</h1>
          <p className="page-subtitle">Every change made through the LAR API, by whom: dashboard staff, in-game staff, and the server itself (imports, auto-bans).</p>
        </div>
      </div>
      <div className="card card-flush">
        <form className="toolbar" onSubmit={e => { e.preventDefault(); setFilter(target.trim()); }}>
          <div className="search-field" style={{maxWidth:360}}><Icon name="search" size={14}/><input placeholder="Filter by target (Player ID, config key, Main/ITEM)…" value={target} onChange={e => setTarget(e.target.value)}/></div>
          <button className="btn btn-sm" type="submit">Filter</button>
          {filter && <button className="btn btn-sm btn-ghost" type="button" onClick={() => { setTarget(""); setFilter(""); }}>Clear</button>}
        </form>
        {error && <div className="tiny" style={{color:"var(--danger)", padding:"0 16px 12px"}}>{error}</div>}
        <table className="tbl">
          <thead><tr><th>Action</th><th>By</th><th>Target</th><th>Detail</th><th style={{textAlign:"right"}}>When</th></tr></thead>
          <tbody>
            {entries.map(e => (
              <tr key={e.id}>
                <td><span className="tag">{e.action}</span></td>
                <td className="tiny">{e.actor}</td>
                <td className="mono tiny">{e.target || "—"}</td>
                <td className="tiny muted mono" style={{maxWidth:360, wordBreak:"break-all"}}>{e.detail == null ? "" : typeof e.detail === "string" ? e.detail : JSON.stringify(e.detail)}</td>
                <td className="tiny muted" style={{textAlign:"right", whiteSpace:"nowrap"}}>{fmtDate(larIso(e.at))}</td>
              </tr>
            ))}
            {!busy && !entries.length && <tr><td colSpan={5}><div className="empty"><h3>Nothing yet</h3><p>Changes show up here as they happen.</p></div></td></tr>}
          </tbody>
        </table>
        {!done && entries.length > 0 && <div style={{padding:12, textAlign:"center"}}><button className="btn btn-sm" disabled={busy} onClick={() => load(false)}>{busy ? "Loading…" : "Load older"}</button></div>}
      </div>
    </div>
  );
}

Object.assign(window, { LarReportsPage, LarMigrationPage, LarAuditPage });
