/* ==================================================================
   Parents → Complaints
   ------------------------------------------------------------------
   The family grievance desk, seen from the office. A parent writes it
   in Adarshabani Parent — the bus, the fee counter, a member of staff,
   how their child was treated — attaches photographs or a PDF, and it
   arrives here and in the teacher app for admin / HoD.

   NOT the student discipline register (screen "complaints" in the
   teacher app / the `complaints` table). That one is a teacher logging
   one student against another and REQUIRES both sides. This is the
   family's own account of something that went wrong, with no accused
   student at all in most cases.

   Closing a complaint requires a note. The server enforces it, and the
   note is shown to the parent verbatim — a family told only "resolved"
   rings the office anyway, which is the thing this register exists to
   stop.

   Endpoints: /api/admin/parent-complaints*  (admin + HoD)

   EVERY TOP-LEVEL NAME HERE IS PREFIXED. The panel's screens are plain
   <script type="text/babel"> files sharing one global scope, so a bare
   `const STATUSES` colliding with another screen's silently kills
   whichever file loads second.
   ================================================================== */

const { Icon: PCxIcon } = window.KXUI;

const PCX_STATUSES = [
  { key: "",              label: "All" },
  { key: "open",          label: "Pending" },
  { key: "investigating", label: "Investigating" },
  { key: "resolved",      label: "Resolved" },
  { key: "dismissed",     label: "Closed" },
];

// `fg` is a TEXT weight, not the saturated fill — these are small pill labels
// on white, and the dark-theme hues are unreadable at this size.
const PCX_STATUS_TINT = {
  open:          { fg: "var(--amber)",  bg: "rgba(255,159,10,.14)",  bd: "rgba(255,159,10,.32)" },
  investigating: { fg: "var(--blue)",   bg: "rgba(59,123,246,.12)",  bd: "rgba(59,123,246,.28)" },
  resolved:      { fg: "var(--green)",  bg: "rgba(47,190,95,.14)",   bd: "rgba(47,190,95,.32)" },
  dismissed:     { fg: "var(--ink-3)",  bg: "rgba(138,138,147,.12)", bd: "rgba(138,138,147,.30)" },
};

const PCX_STATUS_LABEL = {
  open: "Pending", investigating: "Investigating", resolved: "Resolved", dismissed: "Closed",
};

// Mirrors CATEGORIES in backend/src/routes/parent_complaints.ts.
const PCX_CATEGORY_LABEL = {
  academics:  "Teaching & studies",
  teacher:    "A member of staff",
  facilities: "School facilities",
  transport:  "Bus & transport",
  fees:       "Fees & payments",
  safety:     "Safety & wellbeing",
  other:      "Something else",
};

const PCxDate = (iso) => iso
  ? new Date(iso).toLocaleDateString(undefined, { day: "numeric", month: "short", year: "numeric" })
  : "—";

const PCxStatusPill = ({ status }) => {
  const t = PCX_STATUS_TINT[status] || PCX_STATUS_TINT.open;
  return (
    <span style={{
      display: "inline-block", padding: "3px 10px", borderRadius: 999,
      fontSize: 11, whiteSpace: "nowrap",
      color: t.fg, background: t.bg, border: `1px solid ${t.bd}`,
    }}>{PCX_STATUS_LABEL[status] || status}</span>
  );
};

const PCxCard = ({ row, busy, onPatch }) => {
  const [closing, setClosing] = React.useState(null);   // null | 'resolved' | 'dismissed'
  const [note, setNote]       = React.useState("");

  const files = row.attachments || [];
  const open  = row.status === "open" || row.status === "investigating";

  return (
    <div className="cx-card" style={{ padding: 18, marginBottom: 12 }}>
      <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 16 }}>
        <div style={{ minWidth: 0 }}>
          <div style={{ fontSize: 15, color: "var(--ink-0)", fontWeight: 600 }}>
            {PCX_CATEGORY_LABEL[row.category] || "Complaint"}
          </div>
          <div className="muted" style={{ fontSize: 12, marginTop: 3 }}>
            {row.parent_name}
            {row.parent_phone ? <> · <a href={`tel:${row.parent_phone}`} style={{ color: "var(--blue)" }}>{row.parent_phone}</a></> : null}
            {row.student_name ? <> · about {row.student_name}</> : null}
            {row.student_class ? <> · {row.student_class}</> : null}
            {row.student_roll ? <> · Roll {row.student_roll}</> : null}
          </div>
        </div>
        <PCxStatusPill status={row.status}/>
      </div>

      <p style={{
        margin: "12px 0 0", fontSize: 14, lineHeight: 1.6,
        color: "var(--ink-1)", whiteSpace: "pre-wrap",
      }}>{row.about}</p>

      {files.length > 0 && (
        <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginTop: 12 }}>
          {files.map((a, i) => a.mime === "application/pdf" ? (
            <a key={i} href={a.url} target="_blank" rel="noreferrer"
               className="cx-pill"
               style={{ display: "inline-flex", alignItems: "center", gap: 6, textDecoration: "none" }}>
              <PCxIcon name="library" size={13}/> {a.filename || "Document"}
            </a>
          ) : (
            <a key={i} href={a.url} target="_blank" rel="noreferrer" title={a.filename || "Open"}>
              <img src={a.url} alt={a.filename || ""} loading="lazy"
                   style={{
                     height: 96, borderRadius: 8, border: "1px solid var(--hairline)",
                     objectFit: "cover", cursor: "zoom-in", display: "block",
                   }}/>
            </a>
          ))}
        </div>
      )}

      <div className="muted" style={{ fontSize: 11, marginTop: 12 }}>
        Raised {PCxDate(row.created_at)}
        {files.length ? ` · ${files.length} attachment${files.length > 1 ? "s" : ""}` : ""}
      </div>

      {row.resolution_note && (
        <div style={{
          marginTop: 14, paddingTop: 12, borderTop: "1px solid var(--hairline)",
        }}>
          <div className="muted" style={{
            fontSize: 10, letterSpacing: ".08em", textTransform: "uppercase", marginBottom: 4,
          }}>Sent to the parent</div>
          <p style={{
            margin: 0, fontSize: 13, lineHeight: 1.6,
            color: "var(--ink-1)", whiteSpace: "pre-wrap",
          }}>{row.resolution_note}</p>
          {row.resolved_by_name && (
            <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>
              — {row.resolved_by_name}{row.resolved_at ? ` · ${PCxDate(row.resolved_at)}` : ""}
            </div>
          )}
        </div>
      )}

      {/* Closing asks for the note first — the server refuses a close without
          one, so prompting here is the difference between a two-step flow and
          an error message. */}
      {closing ? (
        <div style={{ marginTop: 14, paddingTop: 12, borderTop: "1px solid var(--hairline)" }}>
          <label className="muted" htmlFor={`pcx-note-${row.id}`} style={{
            display: "block", fontSize: 10, letterSpacing: ".08em",
            textTransform: "uppercase", marginBottom: 6,
          }}>What should the parent be told?</label>
          <textarea
            id={`pcx-note-${row.id}`}
            value={note}
            onChange={(e) => setNote(e.target.value)}
            rows={3}
            maxLength={2000}
            placeholder={closing === "resolved"
              ? "What was done about it."
              : "Why this is being closed without further action."}
            style={{
              width: "100%", padding: "10px 12px", borderRadius: 8,
              border: "1px solid var(--hairline)", background: "var(--surface-2)",
              color: "var(--ink-0)", fontSize: 13, lineHeight: 1.6, resize: "vertical",
              fontFamily: "inherit",
            }}/>
          <div style={{ display: "flex", gap: 8, marginTop: 8 }}>
            <button className="cx-btn-dark"
                    disabled={busy || note.trim().length < 3}
                    onClick={() => {
                      onPatch(row, { status: closing, resolution_note: note.trim() });
                      setClosing(null); setNote("");
                    }}>
              {closing === "resolved" ? "Resolve & notify parent" : "Close & notify parent"}
            </button>
            <button className="cx-pill" disabled={busy}
                    onClick={() => { setClosing(null); setNote(""); }}>Cancel</button>
          </div>
        </div>
      ) : (
        <div style={{
          display: "flex", flexWrap: "wrap", gap: 8, marginTop: 14,
          paddingTop: 12, borderTop: "1px solid var(--hairline)",
        }}>
          {row.status === "open" && (
            <button className="cx-pill" disabled={busy}
                    onClick={() => onPatch(row, { status: "investigating" })}>
              Start looking into it
            </button>
          )}
          {open && (
            <>
              <button className="cx-pill" disabled={busy}
                      onClick={() => setClosing("resolved")}>Resolve</button>
              <button className="cx-pill" disabled={busy}
                      onClick={() => setClosing("dismissed")}>Close</button>
            </>
          )}
          {!open && (
            <button className="cx-pill" disabled={busy}
                    onClick={() => onPatch(row, { status: "investigating" })}>Reopen</button>
          )}
        </div>
      )}
    </div>
  );
};

const ParentComplaintsScreen = () => {
  const [rows, setRows]       = React.useState(null);
  const [counts, setCounts]   = React.useState({});
  const [loading, setLoading] = React.useState(true);
  const [err, setErr]         = React.useState(null);
  const [status, setStatus]   = React.useState("");
  const [q, setQ]             = React.useState("");
  const [busy, setBusy]       = React.useState({});

  const load = React.useCallback(async () => {
    setLoading(true); setErr(null);
    try {
      // Always the full list: filtering client-side keeps the tab counts
      // honest (a server-filtered fetch cannot tell you how many are in the
      // tabs you are not looking at) and the register is small.
      const [list, c] = await Promise.all([
        window.KXApi.get("/admin/parent-complaints"),
        window.KXApi.get("/admin/parent-complaints/counts").catch(() => ({})),
      ]);
      setRows(list.complaints || []);
      setCounts(c || {});
    } catch (e) {
      setErr(String(e.message || e));
      setRows([]);
    } finally {
      setLoading(false);
    }
  }, []);

  React.useEffect(() => { load(); }, [load]);

  const patch = async (row, body) => {
    setBusy((b) => ({ ...b, [row.id]: true }));
    try {
      await window.KXApi.patch(`/admin/parent-complaints/${row.id}`, body);
      await load();
    } catch (e) {
      window.alert("Could not update: " + (e.message || e));
    } finally {
      setBusy((b) => { const n = { ...b }; delete n[row.id]; return n; });
    }
  };

  const needle = q.trim().toLowerCase();
  const visible = (rows || []).filter((r) => {
    if (status && r.status !== status) return false;
    if (!needle) return true;
    return [
      r.about, r.parent_name, r.parent_phone, r.student_name, r.student_class,
      PCX_CATEGORY_LABEL[r.category],
    ].filter(Boolean).join(" ").toLowerCase().includes(needle);
  });

  return (
    <div style={{ overflow: "auto", padding: "24px 28px", height: "100%" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 4 }}>
        <span style={{ color: "var(--accent)" }}><PCxIcon name="warn" size={18}/></span>
        <div className="muted" style={{ fontSize: 11, letterSpacing: ".08em", textTransform: "uppercase" }}>
          Parents · grievance desk
        </div>
      </div>

      <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 16, flexWrap: "wrap" }}>
        <div>
          <h1 style={{
            margin: "4px 0 6px", color: "var(--ink-0)",
            fontFamily: "'Instrument Serif', serif", fontWeight: 400,
            fontSize: 32, letterSpacing: "-0.01em",
          }}>Complaints</h1>
          <p className="muted" style={{ margin: 0, fontSize: 13, maxWidth: "62ch", lineHeight: 1.6 }}>
            Raised by families in the Parent app. Every change of state is sent
            straight back to the parent's phone, and closing one needs a note
            they will read.
          </p>
        </div>
        <button className="cx-pill" onClick={load} disabled={loading}>
          {loading ? "Loading…" : "Refresh"}
        </button>
      </div>

      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", margin: "20px 0 12px" }}>
        {PCX_STATUSES.map((s) => {
          const on = status === s.key;
          const n = s.key ? (counts[s.key] ?? 0) : (counts.total ?? (rows?.length ?? 0));
          return (
            <button key={s.key || "all"}
                    className={on ? "cx-pill dark" : "cx-pill"}
                    onClick={() => setStatus(s.key)}>
              {s.label}{rows !== null ? ` · ${n}` : ""}
            </button>
          );
        })}
        <input
          value={q}
          onChange={(e) => setQ(e.target.value)}
          placeholder="Search parent, child or text…"
          aria-label="Search parent complaints"
          style={{
            flex: "1 1 220px", minWidth: 200, padding: "6px 12px", borderRadius: 999,
            border: "1px solid var(--hairline)", background: "var(--surface-2)",
            color: "var(--ink-0)", fontSize: 13, fontFamily: "inherit",
          }}/>
      </div>

      {err && (
        <div className="cx-card" style={{ padding: 16, marginBottom: 12, color: "var(--red)" }}>
          {err}
        </div>
      )}

      {loading && rows === null && (
        <div className="muted" style={{ padding: "40px 0", fontSize: 13 }}>Loading…</div>
      )}

      {rows !== null && visible.length === 0 && !err && (
        <div className="cx-card" style={{ padding: 40, textAlign: "center" }}>
          <div className="muted" style={{ fontSize: 14 }}>
            {q || status ? "Nothing matches that filter." : "No complaints have been raised."}
          </div>
        </div>
      )}

      {visible.map((row) => (
        <PCxCard key={row.id} row={row} busy={!!busy[row.id]} onPatch={patch}/>
      ))}
    </div>
  );
};

window.ParentComplaintsScreen = ParentComplaintsScreen;
