// Source: loaded via <script type="text/babel"> in index.html.
// Manager-only admin for clinical policies. The 7 built-in tau2 policies
// (primekg, benchmark, cardiology, neurology, endocrinology, gastroenterology,
// nephrology) are read-only but offer a "Clone to customize" action that
// creates a custom row with a new id. Custom rows live in D1 via /api/policies
// and are merged onto window.__CAA_POLICIES_CUSTOM by tasksApi.loadPolicies().

function PoliciesPage({ user }) {
  const { t } = useLang();
  const [custom, setCustom] = React.useState(null);       // array of custom policies, null = loading
  const [selectedId, setSelectedId] = React.useState(null);
  const [error, setError] = React.useState(null);
  const [notice, setNotice] = React.useState(null);
  const [pending, setPending] = React.useState(false);
  // Draft state for the currently-selected policy (label + content).
  const [draftLabel, setDraftLabel] = React.useState("");
  const [draftContent, setDraftContent] = React.useState("");

  const builtIns = React.useMemo(() => {
    const meta = window.CAA_POLICY_META || [];
    const bodies = window.CAA_POLICIES || {};
    return meta.map(m => ({
      id: m.id,
      label: m.label,
      content: bodies[m.id] || "",
      builtIn: true,
    }));
  }, []);
  const builtInIds = React.useMemo(() => new Set(builtIns.map(p => p.id)), [builtIns]);

  const loadCustom = React.useCallback(async () => {
    setError(null);
    try {
      if (!window.tasksApi || window.tasksApi.OFFLINE) {
        throw Object.assign(new Error("offline"), { offline: true });
      }
      if (window.tasksApi.invalidatePolicies) window.tasksApi.invalidatePolicies();
      const res = await window.tasksApi.listPolicies();
      const items = Array.isArray(res && res.items) ? res.items : [];
      setCustom(items);
      // Also refresh the global hydrate so Editor sees the same data immediately.
      if (window.tasksApi.loadPolicies) window.tasksApi.loadPolicies().catch(() => {});
    } catch (err) {
      if (err && err.offline) setError("Backend offline — policy management requires a live D1.");
      else setError((err && err.message) || "Failed to load policies.");
      setCustom([]);
    }
  }, []);

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

  // Keep the selection stable across reloads, defaulting to the first entry.
  React.useEffect(() => {
    if (selectedId) return;
    if (builtIns.length) setSelectedId(builtIns[0].id);
  }, [selectedId, builtIns]);

  const allEntries = React.useMemo(() => {
    const customArr = Array.isArray(custom) ? custom : [];
    return [
      ...builtIns,
      ...customArr.filter(c => !builtInIds.has(c.id)).map(c => ({ ...c, builtIn: false })),
    ];
  }, [builtIns, custom, builtInIds]);

  const selected = allEntries.find(p => p.id === selectedId) || null;

  // When the selection changes, reset drafts to the selected row's values.
  React.useEffect(() => {
    if (!selected) { setDraftLabel(""); setDraftContent(""); return; }
    setDraftLabel(selected.label || "");
    setDraftContent(selected.content || "");
  }, [selectedId]); // eslint-disable-line react-hooks/exhaustive-deps

  const dirty = selected && !selected.builtIn && (
    draftLabel !== (selected.label || "") || draftContent !== (selected.content || "")
  );

  const showNotice = (msg) => {
    setNotice(msg);
    window.setTimeout(() => setNotice(n => (n === msg ? null : n)), 3500);
  };

  const onCreate = async () => {
    const idRaw = window.prompt(
      "New policy id (letters, digits, underscore; must start with a letter or underscore; max 64 chars):",
      "",
    );
    if (idRaw == null) return;
    const id = idRaw.trim();
    if (!id) return;
    if (builtInIds.has(id.toLowerCase())) {
      showNotice(`'${id}' is a built-in policy id. Choose a different id.`);
      return;
    }
    if (!/^[a-z_][a-z0-9_]{0,63}$/i.test(id)) {
      showNotice("id must match /^[a-z_][a-z0-9_]{0,63}$/i");
      return;
    }
    const label = window.prompt("Label (human-readable):", id) || id;
    setPending(true);
    try {
      const res = await window.tasksApi.createPolicy({ id, label: label.trim() || id, content: "" });
      await loadCustom();
      setSelectedId((res && res.item && res.item.id) || id);
    } catch (err) {
      showNotice((err && err.body && err.body.error) || (err && err.message) || "Create failed.");
    } finally {
      setPending(false);
    }
  };

  const onClone = async () => {
    if (!selected || !selected.builtIn) return;
    const idRaw = window.prompt(
      `Clone '${selected.id}' to a new custom policy. New id:`,
      `${selected.id}_custom`,
    );
    if (idRaw == null) return;
    const id = idRaw.trim();
    if (!id) return;
    if (builtInIds.has(id.toLowerCase())) {
      showNotice(`'${id}' is a built-in policy id. Choose a different id.`);
      return;
    }
    if (!/^[a-z_][a-z0-9_]{0,63}$/i.test(id)) {
      showNotice("id must match /^[a-z_][a-z0-9_]{0,63}$/i");
      return;
    }
    setPending(true);
    try {
      await window.tasksApi.createPolicy({
        id,
        label: `${selected.label} (custom)`,
        content: selected.content || "",
      });
      await loadCustom();
      setSelectedId(id);
    } catch (err) {
      showNotice((err && err.body && err.body.error) || (err && err.message) || "Clone failed.");
    } finally {
      setPending(false);
    }
  };

  const onSave = async () => {
    if (!selected || selected.builtIn) return;
    const label = draftLabel.trim();
    if (!label) { showNotice("Label cannot be empty."); return; }
    setPending(true);
    try {
      await window.tasksApi.updatePolicy(selected.id, { label, content: draftContent });
      await loadCustom();
      showNotice(`Saved '${selected.id}'.`);
    } catch (err) {
      showNotice((err && err.body && err.body.error) || (err && err.message) || "Save failed.");
    } finally {
      setPending(false);
    }
  };

  const onDelete = async () => {
    if (!selected || selected.builtIn) return;
    const ok = window.confirm(
      `Delete custom policy '${selected.id}'? Tasks that reference it will fall back to 'primekg'. This cannot be undone.`,
    );
    if (!ok) return;
    setPending(true);
    try {
      await window.tasksApi.deletePolicy(selected.id);
      await loadCustom();
      setSelectedId(builtIns[0] ? builtIns[0].id : null);
    } catch (err) {
      showNotice((err && err.body && err.body.error) || (err && err.message) || "Delete failed.");
    } finally {
      setPending(false);
    }
  };

  return (
    <div className="cohorts">
      <div className="cohorts-head">
        <div>
          <div style={{fontSize:11.5, color:"var(--ink-mute)", fontFamily:"var(--font-mono)", textTransform:"uppercase", letterSpacing:"0.06em"}}>Admin · manager</div>
          <h1>{t("nav_policies") || "Policies"}</h1>
          <p>Author custom clinical policies alongside the 7 built-in tau2 policies. Custom policies appear in the editor's policy dropdown immediately.</p>
        </div>
        <div style={{marginLeft:"auto", display:"flex", gap:8, alignItems:"center"}}>
          <button className="btn" onClick={loadCustom} disabled={custom === null || pending}>
            {Ico.reset ? Ico.reset() : null} Refresh
          </button>
          <button className="btn primary" onClick={onCreate} disabled={pending}>
            + New policy
          </button>
        </div>
      </div>

      {notice && (
        <div style={{margin:"0 0 14px", padding:"8px 12px", fontSize:12.5, border:"1px solid var(--line)", background:"var(--bg-sunken)", borderRadius:"var(--r-md)", color:"var(--ink-dim)"}}>
          {notice}
        </div>
      )}
      {error && (
        <div style={{margin:"0 0 14px", padding:"8px 12px", fontSize:12.5, border:"1px solid var(--line)", background:"var(--bg-sunken)", borderRadius:"var(--r-md)", color:"var(--red, #b94a48)"}}>
          {error}
        </div>
      )}

      <div style={{display:"grid", gridTemplateColumns:"280px 1fr", gap:16, alignItems:"start"}}>
        <div style={{border:"1px solid var(--line)", borderRadius:"var(--r-md)", background:"var(--bg)", overflow:"hidden"}}>
          <div style={{padding:"8px 12px", borderBottom:"1px solid var(--line)", fontSize:11, fontFamily:"var(--font-mono)", color:"var(--ink-mute)", textTransform:"uppercase", letterSpacing:"0.06em"}}>
            Built-in (read-only)
          </div>
          {builtIns.map(p => (
            <button
              key={p.id}
              className="nav-item"
              data-active={selectedId === p.id}
              onClick={() => setSelectedId(p.id)}
              style={{width:"100%", borderRadius:0, borderBottom:"1px solid var(--line)"}}
              title={p.label}
            >
              <span style={{width:14}}/>
              <span style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{p.label}</span>
            </button>
          ))}
          <div style={{padding:"8px 12px", borderBottom:"1px solid var(--line)", fontSize:11, fontFamily:"var(--font-mono)", color:"var(--ink-mute)", textTransform:"uppercase", letterSpacing:"0.06em"}}>
            Custom {custom ? `(${(custom || []).filter(c => !builtInIds.has(c.id)).length})` : ""}
          </div>
          {custom === null && (
            <div style={{padding:"12px", color:"var(--ink-mute)", fontSize:12.5}}>Loading…</div>
          )}
          {custom && (custom.filter(c => !builtInIds.has(c.id)).length === 0) && (
            <div style={{padding:"12px", color:"var(--ink-mute)", fontSize:12.5}}>
              No custom policies yet. Use "+ New policy" or clone a built-in.
            </div>
          )}
          {custom && custom.filter(c => !builtInIds.has(c.id)).map(p => (
            <button
              key={p.id}
              className="nav-item"
              data-active={selectedId === p.id}
              onClick={() => setSelectedId(p.id)}
              style={{width:"100%", borderRadius:0, borderBottom:"1px solid var(--line)"}}
              title={p.label}
            >
              <span style={{width:14}}/>
              <span style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{p.label || p.id}</span>
            </button>
          ))}
        </div>

        <div style={{border:"1px solid var(--line)", borderRadius:"var(--r-md)", background:"var(--bg)", padding:16}}>
          {!selected && (
            <div style={{color:"var(--ink-mute)", fontSize:13}}>Select a policy on the left.</div>
          )}
          {selected && (
            <div style={{display:"flex", flexDirection:"column", gap:12}}>
              <div style={{display:"flex", alignItems:"center", gap:8, flexWrap:"wrap"}}>
                <div style={{fontSize:11, fontFamily:"var(--font-mono)", color:"var(--ink-mute)", textTransform:"uppercase", letterSpacing:"0.06em"}}>id</div>
                <code style={{fontSize:13, color:"var(--ink)"}}>{selected.id}</code>
                {selected.builtIn && (
                  <span className="tag" style={{fontFamily:"var(--font-mono)", fontSize:10.5, letterSpacing:"0.03em", textTransform:"uppercase"}}>built-in</span>
                )}
                {!selected.builtIn && (
                  <span className="tag green" style={{fontFamily:"var(--font-mono)", fontSize:10.5, letterSpacing:"0.03em", textTransform:"uppercase"}}>custom</span>
                )}
                {!selected.builtIn && selected.created_by && (
                  <span style={{fontSize:11, color:"var(--ink-mute)", fontFamily:"var(--font-mono)"}}>by {selected.created_by}</span>
                )}
              </div>

              {selected.builtIn && (
                <div style={{padding:"8px 12px", fontSize:12, border:"1px dashed var(--line)", background:"var(--bg-sunken)", borderRadius:"var(--r-md)", color:"var(--ink-dim)"}}>
                  Built-in tau2 policies are read-only. Use <b>Clone to customize</b> to fork this into an editable custom policy with a new id.
                </div>
              )}

              <div>
                <div style={{fontSize:11, fontFamily:"var(--font-mono)", color:"var(--ink-mute)", textTransform:"uppercase", letterSpacing:"0.06em", marginBottom:4}}>Label</div>
                <input
                  className="inp"
                  value={selected.builtIn ? (selected.label || "") : draftLabel}
                  readOnly={selected.builtIn}
                  disabled={selected.builtIn || pending}
                  onChange={e => setDraftLabel(e.target.value)}
                  maxLength={200}
                />
              </div>

              <div>
                <div style={{fontSize:11, fontFamily:"var(--font-mono)", color:"var(--ink-mute)", textTransform:"uppercase", letterSpacing:"0.06em", marginBottom:4}}>
                  Content (markdown) · {(selected.builtIn ? (selected.content || "") : draftContent).length.toLocaleString()} chars
                </div>
                <textarea
                  className="ta"
                  rows={24}
                  value={selected.builtIn ? (selected.content || "") : draftContent}
                  readOnly={selected.builtIn}
                  disabled={selected.builtIn || pending}
                  onChange={e => setDraftContent(e.target.value)}
                  style={{fontFamily:"var(--font-mono)", fontSize:12.5, whiteSpace:"pre"}}
                />
              </div>

              <div style={{display:"flex", gap:8, alignItems:"center"}}>
                {selected.builtIn ? (
                  <button className="btn primary" onClick={onClone} disabled={pending}>
                    Clone to customize
                  </button>
                ) : (
                  <>
                    <button
                      className="btn primary"
                      onClick={onSave}
                      disabled={pending || !dirty}
                      title={dirty ? "Save changes" : "No unsaved changes"}
                    >
                      {pending ? "Saving…" : "Save"}
                    </button>
                    <button className="btn ghost" onClick={onDelete} disabled={pending}>
                      Delete
                    </button>
                    {dirty && (
                      <span style={{fontSize:11.5, color:"var(--ink-mute)", fontFamily:"var(--font-mono)"}}>unsaved changes</span>
                    )}
                  </>
                )}
                <div style={{marginLeft:"auto", fontSize:11, color:"var(--ink-mute)", fontFamily:"var(--font-mono)"}}>
                  {selected.updated_at ? `updated ${selected.updated_at.slice(0, 19).replace("T", " ")}` : ""}
                </div>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

window.PoliciesPage = PoliciesPage;
