/* ==================================================================
   Parents → Complaints
   ------------------------------------------------------------------
   The family grievance desk, seen from the office. A parent writes it
   in the Parent app — 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.AppUI;

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: "color-mix(in srgb, var(--amber-solid) 14%, transparent)",  bd: "color-mix(in srgb, var(--amber-solid) 32%, transparent)" },
  investigating: { fg: "var(--blue)",   bg: "color-mix(in srgb, var(--blue-solid) 12%, transparent)",  bd: "color-mix(in srgb, var(--blue-solid) 28%, transparent)" },
  resolved:      { fg: "var(--green)",  bg: "color-mix(in srgb, var(--green-solid) 14%, transparent)",   bd: "color-mix(in srgb, var(--green-solid) 32%, transparent)" },
  dismissed:     { fg: "var(--ink-3)",  bg: "color-mix(in srgb, var(--ink-0) 12%, transparent)", bd: "color-mix(in srgb, var(--ink-0) 30%, transparent)" },
};

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 PCX_STATUS_TONE = { open: "amber", investigating: "blue", resolved: "green", dismissed: "grey" };

const PCxStatusPill = ({ status }) => (
  <window.AppUI.StatusBadge tone={PCX_STATUS_TONE[status] || "amber"} variant="outline">
    {PCX_STATUS_LABEL[status] || status}
  </window.AppUI.StatusBadge>
);

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={{ marginBottom: 16 }}>
      <div style={{ display: "flex", alignItems: "flex-start", gap: 14 }}>
        <window.AppUI.Avatar name={row.parent_name} size="lg"/>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
            <div className="cx-card-title">{PCX_CATEGORY_LABEL[row.category] || "Complaint"}</div>
            <PCxStatusPill status={row.status}/>
          </div>
          <div className="muted" style={{ fontSize: 13, marginTop: 4, display: "flex", flexWrap: "wrap", gap: "2px 12px" }}>
            <span>{row.parent_name}</span>
            {row.parent_phone ? <a href={`tel:${row.parent_phone}`} style={{ color: "var(--blue)" }} className="tabular">{row.parent_phone}</a> : null}
            {row.student_name ? <span>about {row.student_name}</span> : null}
            {row.student_class ? <span>{row.student_class}</span> : null}
            {row.student_roll ? <span>Roll <span className="mono">{row.student_roll}</span></span> : null}
          </div>
        </div>
        {row.parent_phone && (
          <a href={`tel:${row.parent_phone}`} className="ui-iconbtn ghost" title="Call parent" aria-label="Call parent">
            <PCxIcon name="phone" size={16}/>
          </a>
        )}
      </div>

      <p style={{
        margin: "16px 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: 14 }}>
          {files.map((a, i) => a.mime === "application/pdf" ? (
            <a key={i} href={a.url} target="_blank" rel="noreferrer" className="btn sm"
               style={{ textDecoration: "none" }}>
              <PCxIcon name="library" size={14}/>{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: "var(--radius-tile)", border: "1px solid var(--line)",
                     objectFit: "cover", cursor: "zoom-in", display: "block",
                   }}/>
            </a>
          ))}
        </div>
      )}

      <div className="muted" style={{ fontSize: 12, marginTop: 14, display: "flex", alignItems: "center", gap: 6 }}>
        <PCxIcon name="clock" size={13}/>
        Raised {PCxDate(row.created_at)}
        {files.length ? ` · ${files.length} attachment${files.length > 1 ? "s" : ""}` : ""}
      </div>

      {row.resolution_note && (
        <div className="cx-tile" style={{ marginTop: 16 }}>
          <div className="ui-section-label" style={{ marginBottom: 6 }}>Sent to the parent</div>
          <p style={{
            margin: 0, fontSize: 13.5, lineHeight: 1.6,
            color: "var(--ink-1)", whiteSpace: "pre-wrap",
          }}>{row.resolution_note}</p>
          {row.resolved_by_name && (
            <div className="muted" style={{ fontSize: 12, marginTop: 6 }}>
              — {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 className="cx-card-foot" style={{ display: "block" }}>
          <div className="field" style={{ margin: 0 }}>
            <label className="label" htmlFor={`pcx-note-${row.id}`}>What should the parent be told?</label>
            <textarea
              className="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%", resize: "vertical" }}/>
          </div>
          <div style={{ display: "flex", gap: 8, marginTop: 10, justifyContent: "flex-end" }}>
            <button className="btn" disabled={busy}
                    onClick={() => { setClosing(null); setNote(""); }}>Cancel</button>
            <button className="btn primary"
                    disabled={busy || note.trim().length < 3}
                    onClick={() => {
                      onPatch(row, { status: closing, resolution_note: note.trim() });
                      setClosing(null); setNote("");
                    }}>
              <PCxIcon name={closing === "resolved" ? "checkCircle" : "xCircle"} size={15}/>
              {closing === "resolved" ? "Resolve & notify parent" : "Close & notify parent"}
            </button>
          </div>
        </div>
      ) : (
        <div className="cx-card-foot" style={{ justifyContent: "flex-start", flexWrap: "wrap", gap: 8 }}>
          {row.status === "open" && (
            <button className="btn" disabled={busy}
                    onClick={() => onPatch(row, { status: "investigating" })}>
              <PCxIcon name="search" size={15}/>Start looking into it
            </button>
          )}
          {open && (
            <>
              <button className="btn" disabled={busy}
                      onClick={() => setClosing("resolved")}><PCxIcon name="checkCircle" size={15}/>Resolve</button>
              <button className="btn" disabled={busy}
                      onClick={() => setClosing("dismissed")}><PCxIcon name="xCircle" size={15}/>Close</button>
            </>
          )}
          {!open && (
            <button className="btn" disabled={busy}
                    onClick={() => onPatch(row, { status: "investigating" })}><PCxIcon name="refresh" size={15}/>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.AppApi.get("/admin/parent-complaints"),
        window.AppApi.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.AppApi.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", height: "100%" }}>
    <div className="cx-page" style={{ maxWidth: 1100 }}>
      <window.AppUI.PageHeader
        eyebrow="Parents · grievance desk"
        title="Complaints"
        status={counts.open ? <window.AppUI.StatusBadge tone="amber" variant="outline">{counts.open} pending</window.AppUI.StatusBadge> : null}
        meta={["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."]}
        actions={
          <button className="btn" onClick={load} disabled={loading}>
            <PCxIcon name="refresh" size={15}/>{loading ? "Loading…" : "Refresh"}
          </button>
        }
      />

      <div style={{ display: "flex", gap: 12, flexWrap: "wrap", alignItems: "center", marginBottom: 20 }}>
        <window.AppUI.Tabs value={status} onChange={setStatus} ariaLabel="Complaint status"
          items={PCX_STATUSES.map((s) => ({
            value: s.key, label: s.label,
            count: rows !== null ? (s.key ? (counts[s.key] ?? 0) : (counts.total ?? (rows?.length ?? 0))) : undefined,
          }))}/>
        <div className="ui-search" style={{ flex: "1 1 220px", minWidth: 200 }}>
          <PCxIcon name="search" size={14}/>
          <input
            className="input"
            value={q}
            onChange={(e) => setQ(e.target.value)}
            placeholder="Search parent, child or text…"
            aria-label="Search parent complaints"/>
        </div>
      </div>

      {err && <div className="ui-alert red" style={{ marginBottom: 16 }}>{err}</div>}

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

      {rows !== null && visible.length === 0 && !err && (
        <window.AppUI.EmptyState card icon="inbox"
          title={q || status ? "Nothing matches that filter." : "No complaints have been raised."}/>
      )}

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

window.ParentComplaintsScreen = ParentComplaintsScreen;
