// reported-mods-panel.jsx - ReportedModsPanel component + helpers
// Loaded after sortof-shared.jsx; defines globals that sortof-app.jsx references.
const { useState, useEffect, useMemo } = React;

function fmtReportDate(iso) {
  if (!iso) return '';
  const d = new Date(iso);
  if (isNaN(d.getTime())) return iso;
  const pad = (n) => String(n).padStart(2, '0');
  const HH = pad(d.getUTCHours());
  const MM = pad(d.getUTCMinutes());
  const mo = pad(d.getUTCMonth() + 1);
  const da = pad(d.getUTCDate());
  const yy = d.getUTCFullYear();
  return `${HH}:${MM} ${mo}-${da}-${yy}`;
}

const _VOTED_KEY = 'sortof.brokenmod.voted';
function loadVoted() {
  try { return JSON.parse(localStorage.getItem(_VOTED_KEY) || '{}') || {}; }
  catch { return {}; }
}
function saveVoted(v) {
  try { localStorage.setItem(_VOTED_KEY, JSON.stringify(v)); } catch {}
}

function ReportedModsPanel({ onClose }) {
  const [versions, setVersions] = useState({});
  const [reports, setReports]   = useState([]);
  const [search, setSearch]     = useState('');
  const [wsidIn, setWsidIn]     = useState('');
  const [verIn, setVerIn]       = useState('');
  const [submitting, setSubmitting] = useState(false);
  const [error, setError]       = useState('');
  const [voted, setVoted]       = useState(loadVoted());

  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const [vRes, rRes] = await Promise.all([
          fetch('/api/pz-versions').then(r => r.json()),
          fetch('/api/broken-mods').then(r => r.json()),
        ]);
        if (cancelled) return;
        setVersions(vRes || {});
        setReports(Array.isArray(rRes) ? rRes : []);
        const firstKey = Object.keys(vRes || {})[0];
        if (firstKey) setVerIn(firstKey);
      } catch (e) {
        if (!cancelled) setError(`load failed: ${e?.message || e}`);
      }
    })();
    return () => { cancelled = true; };
  }, []);

  async function onSubmit(e) {
    e.preventDefault();
    setError('');
    const wsid = (wsidIn || '').trim();
    if (!/^\d+$/.test(wsid)) {
      setError('workshop id must be digits only');
      return;
    }
    if (!verIn) {
      setError('pick a version');
      return;
    }
    setSubmitting(true);
    try {
      const res = await fetch('/api/broken-mods', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ workshop_id: wsid, version: verIn }),
      });
      if (!res.ok) {
        const txt = await res.text();
        setError(`submit failed: ${res.status} ${txt}`);
        return;
      }
      setWsidIn('');
      const list = await fetch('/api/broken-mods').then(r => r.json());
      setReports(Array.isArray(list) ? list : []);
    } catch (e) {
      setError(`network error: ${e?.message || e}`);
    } finally {
      setSubmitting(false);
    }
  }

  async function onVote(id, direction) {
    if (voted[id]) return;
    try {
      const res = await fetch(`/api/broken-mods/${id}/vote`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ direction }),
      });
      if (!res.ok) return;
      const counts = await res.json();
      setReports(prev => prev.map(r => r.id === id
        ? { ...r, upvotes: counts.upvotes, downvotes: counts.downvotes }
        : r));
      const next = { ...voted, [id]: direction };
      setVoted(next);
      saveVoted(next);
    } catch {}
  }

  const filtered = useMemo(() => {
    const q = (search || '').trim().toLowerCase();
    if (!q) return reports;
    return reports.filter(r =>
      (r.workshop_id || '').toLowerCase().includes(q) ||
      (r.mod_name || '').toLowerCase().includes(q),
    );
  }, [reports, search]);

  return (
    <main className="reports-panel">
      <div className="reports-head">
        <div className="reports-title">Reported broken mods</div>
        <div className="reports-blurb">
          add a workshop id + which PZ build it broke on. duplicates of the
          same (id, version) bubble back to the top with their existing votes.
        </div>
        <form className="reports-form" onSubmit={onSubmit}>
          <input
            className="field"
            aria-label="workshop item id"
            type="text"
            placeholder="workshop id (e.g. 2613146550)"
            value={wsidIn}
            onChange={(e) => setWsidIn(e.target.value)}
            inputMode="numeric"
            spellCheck={false}
          />
          <select
            className="field"
            aria-label="mod version"
            value={verIn}
            onChange={(e) => setVerIn(e.target.value)}
          >
            {Object.entries(versions).map(([k, v]) => (
              <option key={k} value={k}>{v} ({k})</option>
            ))}
          </select>
          <button
            type="submit"
            className="sort-btn"
            disabled={submitting || !wsidIn.trim() || !verIn}
          >
            {submitting ? '…submitting' : '+ report'}
          </button>
        </form>
        {error && <div className="reports-error">{error}</div>}
        <input
          className="field reports-search"
          aria-label="search reported mods"
          type="text"
          placeholder="search by workshop id or mod name…"
          value={search}
          onChange={(e) => setSearch(e.target.value)}
        />
        <div className="reports-meta">
          {filtered.length} {filtered.length === 1 ? 'report' : 'reports'}
          {search && reports.length !== filtered.length
            ? ` (of ${reports.length})` : ''}
        </div>
      </div>
      <ul className="reports-list">
        {filtered.length === 0 && (
          <li className="reports-empty">no reports yet - be the first.</li>
        )}
        {filtered.map(r => {
          const v = voted[r.id];
          const verLabel = versions[r.version] || r.version;
          return (
            <li key={r.id} className="report-row">
              <div className="report-name">
                <WsidLink wsid={r.workshop_id}>
                  {r.mod_name || r.workshop_id}
                </WsidLink>
              </div>
              <div className="report-wsid">{r.workshop_id}</div>
              <div className="report-ver">
                <span className="cat ver-pill" title={r.version}>{verLabel}</span>
              </div>
              <div className="report-date">{fmtReportDate(r.updated_at)}</div>
              <div className="report-votes">
                <button
                  type="button"
                  className={'vote-btn up' + (v === 'up' ? ' voted' : '')}
                  onClick={() => onVote(r.id, 'up')}
                  disabled={!!v}
                  title={v === 'up' ? 'you upvoted' : 'agree (broken)'}
                >▲ {r.upvotes}</button>
                <button
                  type="button"
                  className={'vote-btn down' + (v === 'down' ? ' voted' : '')}
                  onClick={() => onVote(r.id, 'down')}
                  disabled={!!v}
                  title={v === 'down' ? 'you downvoted' : 'disagree (works for me)'}
                >▼ {r.downvotes}</button>
              </div>
            </li>
          );
        })}
      </ul>
    </main>
  );
}

Object.assign(window, { ReportedModsPanel, fmtReportDate, loadVoted, saveVoted });
