/* === Milestone detail panel — RAG rating, rationale, numeric override ===
   Spec §3: a written rationale is REQUIRED for any Yellow or Red (Pew board
   convention) — the form enforces it. Numeric milestones carry a human
   override of the auto-computed counts (judgment calls must be correctable).
   Milestones are board-level: admins edit, everyone else reads. */

function MilestonePanel({ id, onClose }) {
  const m = window.MILESTONES.find((x) => x.id === id);
  const me = window.Store.session();
  const canEdit = !!(me && me.role === "admin");

  const [history, setHistory] = React.useState(null);
  const [err, setErr] = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  // Edit form state
  const [rag, setRag] = React.useState(m ? m.rag : "green");
  const [rationale, setRationale] = React.useState((m && m.rationale && m.rationale.text) || "");
  const [current, setCurrent] = React.useState(m ? m.current : null);
  const [secondaryCurrent, setSecondaryCurrent] = React.useState(m ? m.secondaryCurrent : null);
  React.useEffect(() => {
    if (!m) return;
    setRag(m.rag);
    setRationale((m.rationale && m.rationale.text) || "");
    setCurrent(m.current);
    setSecondaryCurrent(m.secondaryCurrent);
  }, [id]);

  const refreshHistory = React.useCallback(() => {
    window.Store.history({ type: "milestone", id }).then(setHistory).catch(() => setHistory([]));
  }, [id]);
  React.useEffect(() => { setHistory(null); refreshHistory(); }, [id, refreshHistory]);

  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  if (!m) return null;

  const isNumeric = m.kind === "numeric";
  const ragDirty = rag !== m.rag || rationale !== ((m.rationale && m.rationale.text) || "");
  const numDirty = isNumeric && (Number(current) !== m.current ||
    (m.secondaryTarget != null && Number(secondaryCurrent) !== m.secondaryCurrent));
  const rationaleMissing = (rag === "yellow" || rag === "red") && !rationale.trim();

  async function save() {
    if (rationaleMissing) { setErr("Yellow and Red require a written rationale (board convention)."); return; }
    setBusy(true); setErr(null);
    const patch = {}, prev = {};
    if (rag !== m.rag) { patch.rag = rag; prev.rag = m.rag; }
    const newRationale = (rag === "green")
      ? (rationale.trim() ? { label: "NOTE", text: rationale.trim() } : null)
      : { label: `RATIONALE (${rag.toUpperCase()})`, text: rationale.trim() };
    if (JSON.stringify(newRationale) !== JSON.stringify(m.rationale || null)) {
      patch.rationale = newRationale; prev.rationale = m.rationale || null;
    }
    if (isNumeric && Number(current) !== m.current) { patch.current = Number(current); prev.current = m.current; }
    if (isNumeric && m.secondaryTarget != null && Number(secondaryCurrent) !== m.secondaryCurrent) {
      patch.secondaryCurrent = Number(secondaryCurrent); prev.secondaryCurrent = m.secondaryCurrent;
    }
    if (!Object.keys(patch).length) { setBusy(false); return; }
    try {
      await window.Store.commit({ entityType: "milestone", entityId: id, action: "update", patch, prev });
      refreshHistory();
    } catch (e) {
      setErr(String(e.message || e));
    } finally {
      setBusy(false);
    }
  }

  const numInput = {
    width: 80, padding: "6px 8px", borderRadius: 4, border: "1px solid var(--border)",
    background: "var(--surface-2)", font: "600 14px/1 var(--mono)", outline: "none", textAlign: "center",
  };

  return (
    <>
      <div className="scrim is-open" onClick={onClose}></div>
      <aside className="side-panel is-open">
        <div className="side-panel__head">
          <button className="side-panel__close" onClick={onClose} title="Close">
            <svg width="14" height="14" viewBox="0 0 14 14"><path d="M3 3 L11 11 M11 3 L3 11" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" /></svg>
          </button>
          <div className="side-panel__eyebrow">Milestone · {m.id} · {m.glyph} {m.kind}</div>
          <div className="side-panel__title" style={{ fontSize: 18, lineHeight: 1.3 }}>{m.title}</div>
          <div style={{ marginTop: 10, display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
            {m.oda.map((o) => <ODAChip key={o} id={o} withTitle />)}
            <span className="chip chip--soft">{m.workItems} work items</span>
            <RagBadge rag={m.rag} />
          </div>
          {!canEdit ? (
            <div className="mono faint" style={{ fontSize: 10, marginTop: 8, letterSpacing: ".08em", textTransform: "uppercase" }}>
              board-rated — admins edit
            </div>
          ) : null}
        </div>

        {/* Numeric progress + override */}
        {isNumeric ? (
          <div className="side-panel__section">
            <h4>Progress {canEdit ? "· human override" : ""}</h4>
            <div className="row" style={{ gap: 16, flexWrap: "wrap" }}>
              <div>
                <div className="eyebrow" style={{ marginBottom: 4 }}>{m.unit}</div>
                <div className="row" style={{ gap: 6 }}>
                  {canEdit
                    ? <input type="number" style={numInput} value={current ?? ""} onChange={(e) => setCurrent(e.target.value)} />
                    : <span style={{ fontFamily: "var(--serif)", fontSize: 22, fontWeight: 600 }}>{m.current}</span>}
                  <span className="mono faint">/ {m.target}</span>
                </div>
              </div>
              {m.secondaryTarget != null ? (
                <div>
                  <div className="eyebrow" style={{ marginBottom: 4 }}>{m.secondaryLabel || "secondary"}</div>
                  <div className="row" style={{ gap: 6 }}>
                    {canEdit
                      ? <input type="number" style={numInput} value={secondaryCurrent ?? ""} onChange={(e) => setSecondaryCurrent(e.target.value)} />
                      : <span style={{ fontFamily: "var(--serif)", fontSize: 22, fontWeight: 600 }}>{m.secondaryCurrent}</span>}
                    <span className="mono faint">/ {m.secondaryTarget}</span>
                  </div>
                </div>
              ) : null}
            </div>
            <div style={{ marginTop: 10 }}>
              <ProgressBar value={Number(canEdit ? current : m.current) || 0} max={m.target} rag={m.rag} />
            </div>
            <div className="mono faint" style={{ fontSize: 10, marginTop: 6 }}>
              Counts auto-compute from linked work; the override exists for judgment calls (e.g. what counts as "introduced").
            </div>
          </div>
        ) : (
          <div className="side-panel__section">
            <h4>Qualitative</h4>
            <div className="muted" style={{ fontSize: 12 }}>No numeric denominator — hand-rated with a written rationale. Never shown as a percentage.</div>
          </div>
        )}

        {/* RAG + rationale */}
        <div className="side-panel__section">
          <h4>Board rating (RAG)</h4>
          {canEdit ? (
            <>
              <div className="row" style={{ gap: 8 }}>
                {["green", "yellow", "red"].map((r) => (
                  <button key={r} type="button" onClick={() => setRag(r)}
                    style={{
                      padding: "6px 14px", borderRadius: 4, cursor: "pointer",
                      border: `1px solid ${rag === r ? `var(--${r})` : "var(--border)"}`,
                      background: rag === r ? `var(--${r}-bg)` : "var(--surface)",
                      color: rag === r ? `var(--${r})` : "var(--ink-mute)",
                      font: "600 11px/1 var(--serif)", letterSpacing: ".06em",
                    }}>
                    {r.toUpperCase()}
                  </button>
                ))}
              </div>
              <div style={{ marginTop: 12 }}>
                <div className="eyebrow" style={{ marginBottom: 4 }}>
                  {rag === "green" ? "Note (optional)" : `Rationale — required for ${rag}`}
                </div>
                <textarea rows={4} value={rationale} onChange={(e) => setRationale(e.target.value)}
                  placeholder={rag === "green" ? "Optional context." : "The written paragraph the board sees — why this is " + rag + " and the path back."}
                  style={{
                    width: "100%", padding: "8px 10px", borderRadius: 4,
                    border: `1px solid ${rationaleMissing ? "var(--red)" : "var(--border)"}`,
                    background: "var(--surface-2)", font: "400 13px/1.5 var(--sans)", outline: "none", resize: "vertical",
                  }} />
              </div>
              {err ? (
                <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: 4, background: "var(--red-bg)", color: "var(--red)", fontSize: 12 }}>{err}</div>
              ) : null}
              {(ragDirty || numDirty) ? (
                <div className="row" style={{ marginTop: 12, gap: 8 }}>
                  <button className="btn btn--primary" disabled={busy || rationaleMissing} onClick={save}>
                    {busy ? "Saving…" : "Save rating"}
                  </button>
                  <button className="btn btn--ghost" onClick={() => {
                    setRag(m.rag); setRationale((m.rationale && m.rationale.text) || "");
                    setCurrent(m.current); setSecondaryCurrent(m.secondaryCurrent); setErr(null);
                  }}>Cancel</button>
                </div>
              ) : null}
            </>
          ) : (
            <>
              <RagBadge rag={m.rag} />
              {m.rationale ? (
                <div className={`milestone-row__rationale ${m.rag === "red" ? "is-red" : ""}`} style={{ marginTop: 10 }}>
                  <strong>{m.rationale.label}</strong>
                  {m.rationale.text}
                </div>
              ) : null}
            </>
          )}
        </div>

        {canEdit ? (
          <div className="side-panel__section">
            <DeleteButton label={`Delete ${m.id}`} busy={busy}
              onDelete={async () => {
                setBusy(true); setErr(null);
                try {
                  await window.Store.commit({ entityType: "milestone", entityId: id, action: "delete", prev: { title: m.title }, note: "deleted" });
                  onClose();
                } catch (e) { setErr(String(e.message || e)); setBusy(false); }
              }} />
          </div>
        ) : null}

        {/* History */}
        <div className="side-panel__section">
          <details open={false}>
            <summary style={{ cursor: "pointer", font: "500 11px/1 var(--mono)", letterSpacing: ".14em", color: "var(--ink-mute)", textTransform: "uppercase" }}>
              Rating & edit history {history ? `(${history.length})` : ""}
            </summary>
            <div style={{ marginTop: 10 }}>
              {history === null ? (
                <div className="row" style={{ gap: 8, color: "var(--ink-mute)", fontSize: 12 }}><span className="spinner"></span> Loading…</div>
              ) : history.length === 0 ? (
                <div className="muted" style={{ fontSize: 12 }}>No recorded changes yet.</div>
              ) : history.map((e, i) => (
                <div key={i} style={{ padding: "8px 0", borderTop: "1px solid var(--rule)" }}>
                  <div className="row row--between">
                    <span className="mono" style={{ fontSize: 11, color: "var(--ink-2)", fontWeight: 600 }}>{e.user_name || "?"}</span>
                    <span className="mono faint" style={{ fontSize: 10 }}>{fmtEventTs(e.ts)}</span>
                  </div>
                  <div style={{ fontSize: 12, color: "var(--ink-2)", marginTop: 3 }}>
                    {Object.keys(e.patch || {}).map((k) => (
                      <div key={k}>
                        <span className="mono faint" style={{ fontSize: 10, textTransform: "uppercase", letterSpacing: ".08em" }}>{k}</span>{" "}
                        <span className="faint">{fmtVal(e.prev && e.prev[k])}</span> <span className="faint">→</span> {fmtVal(e.patch[k])}
                      </div>
                    ))}
                  </div>
                </div>
              ))}
            </div>
          </details>
        </div>
      </aside>
    </>
  );
}

Object.assign(window, { MilestonePanel });
