/* bugs.jsx — "Report a bug" for everyone + the owner's Bugs triage tab.
   Any signed-in user files a report from the sidebar button (modal); reports
   land in tape_bug_reports and surface in the owner-only Bugs tab with
   open → resolved/dismissed triage.
*/

const BUG_CATEGORIES = [["bug", "Bug"], ["idea", "Idea"], ["other", "Other"]];

// ── The modal every user can open (sidebar → Report a bug) ──────────────────
function BugReportModal({ tab, onClose, onSubmitted }) {
  const [category, setCategory] = useState("bug");
  const [message, setMessage] = useState("");
  const [busy, setBusy] = useState(false);
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape" && !busy) onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [busy]);

  async function submit() {
    if (busy) return;
    if (message.trim().length < 10) { toast.error("Please describe it in a little more detail (10+ characters)."); return; }
    setBusy(true);
    try {
      await tapeSend(apiBase() + "/api/bugs", {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({
          category,
          message: message.trim(),
          // Attached automatically so reports are diagnosable without back-and-forth.
          context: {
            version: typeof APP_VERSION !== "undefined" ? APP_VERSION : "?",
            tab: tab || "?",
            viewport: `${window.innerWidth}×${window.innerHeight}`,
            theme: document.documentElement.getAttribute("data-theme") || "?",
            userAgent: navigator.userAgent,
          },
        }),
      });
      toast.success("Thanks — your report is in. We're on it.");
      onSubmitted && onSubmitted();
      onClose();
    } catch (err) {
      toast.error("Couldn't send — " + err.message);
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="modal-back" onMouseDown={() => !busy && onClose()}>
    <div className="modal manage-modal" role="dialog" aria-modal="true" onMouseDown={(e) => e.stopPropagation()}>
      <div className="calc-hdr">
        <div>
          <div className="calc-title">{I("bug", { size: 16 })} Report a bug</div>
          <div className="calc-sub mono">Spotted something broken? Have an idea?</div>
        </div>
        <button className="icon-btn" title="Close" onClick={onClose}>{I("close", { size: 16 })}</button>
      </div>
      <div className="manage-body">
        <div className="seg manage-actions">
          {BUG_CATEGORIES.map(([v, l]) => (
            <button key={v} className={cx("seg-btn", category === v && "on")} onClick={() => setCategory(v)}>{l}</button>
          ))}
        </div>
        <label className="calc-field">
          <span>What happened? What did you expect instead?</span>
          <textarea
            className="manage-note" rows={5} autoFocus
            value={message} onChange={e => setMessage(e.target.value)}
            placeholder={category === "idea"
              ? "e.g. It would be great if the watchlist could…"
              : "e.g. On the Positions tab, when I tap a NVDA row, the timeline shows…"}
          />
        </label>
        <div className="manage-foot">
          <button className="btn" onClick={onClose} disabled={busy}>Cancel</button>
          <button className="btn primary" onClick={submit} disabled={busy}>{busy ? "Sending…" : "Send report"}</button>
        </div>
        <div className="manage-disclaimer">Your name, role, app version and current page are attached automatically so we can reproduce it — no other data is collected.</div>
      </div>
    </div>
    </div>
  );
}

// ── Owner-only triage tab ────────────────────────────────────────────────────
const BUG_STATUS_META = {
  open:      { label: "open",      color: "var(--c-trim)" },
  resolved:  { label: "resolved",  color: "var(--c-open)" },
  dismissed: { label: "dismissed", color: "var(--fg-3)" },
};

function BugsTab({ onOpenCountChange }) {
  const [status, setStatus] = useState("open");
  const [reports, setReports] = useState(null);
  const [err, setErr] = useState(null);
  const avatars = useAvatars((reports || []).map(r => r.reporter_id));

  function load() {
    setErr(null);
    tapeFetch(apiBase() + "/api/bugs?status=" + status)
      .then(async r => { const j = await r.json(); if (!r.ok) throw new Error(j.error || "HTTP " + r.status); return j; })
      .then(j => setReports(j.reports || []))
      .catch(e => setErr(e.message));
  }
  useEffect(() => { setReports(null); load(); }, [status]);

  async function setStatusFor(rep, next) {
    setReports(prev => prev.map(r => r.id === rep.id ? { ...r, status: next } : r));
    try {
      await tapeSend(apiBase() + "/api/bugs/" + rep.id, {
        method: "PATCH", headers: { "content-type": "application/json" }, body: JSON.stringify({ status: next }),
      });
      onOpenCountChange && onOpenCountChange(next === "open" ? +1 : (rep.status === "open" ? -1 : 0));
      if (status !== "all") setReports(prev => prev.filter(r => r.id !== rep.id || next === status));
    } catch (e2) {
      setReports(prev => prev.map(r => r.id === rep.id ? { ...r, status: rep.status } : r));
      toast.error("Couldn't update — " + e2.message);
    }
  }
  async function remove(rep) {
    if (!(await confirmDialog({ title: "Delete report", message: "Delete this report permanently?", confirmLabel: "Delete", danger: true }))) return;
    setReports(prev => prev.filter(r => r.id !== rep.id));
    try {
      await tapeSend(apiBase() + "/api/bugs/" + rep.id, { method: "DELETE" });
      if (rep.status === "open") onOpenCountChange && onOpenCountChange(-1);
      toast.success("Report deleted");
    } catch (e2) {
      setReports(prev => prev.some(r => r.id === rep.id) ? prev : [rep, ...prev]);
      toast.error("Couldn't delete — " + e2.message);
    }
  }

  const ctxLine = (c) => {
    if (!c) return null;
    const bits = [];
    if (c.version) bits.push("v" + c.version);
    if (c.tab) bits.push(c.tab);
    if (c.viewport) bits.push(c.viewport);
    if (c.theme) bits.push(c.theme);
    return bits.join(" · ");
  };

  return (
    <div className="bugs">
      <div className="usage-head">
        <p className="sub" style={{ margin: 0 }}>Bug reports and ideas filed by users via the sidebar's "Report a bug" button.</p>
        <div className="seg">
          {["open", "resolved", "dismissed", "all"].map(s => (
            <button key={s} className={cx("seg-btn", status === s && "on")} onClick={() => setStatus(s)}>{s}</button>
          ))}
        </div>
      </div>

      {err && <div className="empty" style={{ padding: 30 }}>Couldn't load reports — {err}</div>}
      {!err && reports === null && <div className="empty" style={{ padding: 30 }}>Loading…</div>}
      {!err && reports !== null && reports.length === 0 && (
        <div className="empty" style={{ padding: 40 }}>{status === "open" ? "No open reports — inbox zero. 🎉" : "Nothing here."}</div>
      )}

      {(reports || []).map(rep => {
        const meta = BUG_STATUS_META[rep.status] || BUG_STATUS_META.open;
        return (
          <div key={rep.id} className="panel bug-card">
            <div className="bug-card-hdr">
              <span className="bug-status mono" style={{ color: meta.color, borderColor: meta.color }}>{meta.label}</span>
              <span className="bug-cat mono">{rep.category}</span>
              <span className="usage-user">
                <DiscordAvatar url={avatars[rep.reporter_id]} size={18} fallback={<span className="hash">{I("user", { size: 12 })}</span>} />
                <span>{rep.reporter_name || rep.reporter_id}</span>
                {rep.reporter_role && <span className="usage-role mono">{rep.reporter_role}</span>}
              </span>
              <span className="bug-time mono">{fmtTime(new Date(rep.ts).getTime(), { short: true })}</span>
              <span className="bug-actions">
                {rep.status !== "resolved" && <button className="icon-btn" title="Mark resolved" onClick={() => setStatusFor(rep, "resolved")}>{I("check", { size: 15 })}</button>}
                {rep.status === "open" && <button className="icon-btn" title="Dismiss" onClick={() => setStatusFor(rep, "dismissed")}>{I("close", { size: 15 })}</button>}
                {rep.status !== "open" && <button className="icon-btn" title="Reopen" onClick={() => setStatusFor(rep, "open")}>{I("refresh", { size: 14 })}</button>}
                <button className="icon-btn danger" title="Delete report" onClick={() => remove(rep)}>{I("trash", { size: 14 })}</button>
              </span>
            </div>
            <div className="bug-msg">{rep.message}</div>
            {ctxLine(rep.context) && <div className="bug-ctx mono">{ctxLine(rep.context)}</div>}
          </div>
        );
      })}
    </div>
  );
}

Object.assign(window, { BugReportModal, BugsTab });
