/* Agencies by place (G2, spec agencies-by-location-v1). The Agencies page's "By place"
   view: every state → one state (its links, FOIA rules, statewide agencies, counties) →
   one county (the state's links plus the county's own, then its courts and their courthouses
   (G4, Content Ops only), sheriff and police, prosecutor and the rest). Lacey's "open Maricopa and see everything about working there".

   Reads the directory rows the Agencies page already fetched (every agency, filtered in the
   browser, as that page does) plus two small tables: state_resources and state_foia_rules
   (0149). Writes go through RPCs: links by anyone in Workspace (D11), FOIA rules by Content
   Ops. Assigns window.LedgerAgencyPlaces. */
(function () {
  const DS = window.LawCrimeDesignSystem_e18d68;
  const T = window.titleize;
  const icons = () => setTimeout(() => window.lucide && window.lucide.createIcons(), 30);
  const stateName = (s) => (window.LEDGER_STATE_NAME && window.LEDGER_STATE_NAME[s]) || s;
  const countyTitle = (county, sample) => county + window.agencyCountyWord(sample || {});

  // Kinds mirror state_resources.kind (0149).
  const KINDS = ["case_search", "court_directory", "live_stream_directory", "foia_portal", "statute", "other"];
  const KIND_LABEL = { case_search: "Case search", court_directory: "Court directory", live_stream_directory: "Live-stream directory",
                       foia_portal: "FOIA portal", statute: "Statute", other: "Other" };
  const KIND_ICON = { case_search: "search", court_directory: "landmark", live_stream_directory: "video",
                      foia_portal: "file-text", statute: "scale", other: "link" };

  // The county panel's sections, in the spec's order (courts, then law enforcement, then
  // prosecutors). Anything else lands in Other.
  const GROUPS = [
    { key: "court", label: "Courts", types: ["court"] },
    { key: "le", label: "Sheriff and police", types: ["sheriff", "police_department"] },
    { key: "pros", label: "Prosecutor", types: ["prosecutor_office"] },
  ];
  const groupOf = (t) => (GROUPS.find((g) => g.types.includes(t)) || { key: "other" }).key;
  const GROUP_LABEL = GROUPS.reduce((m, g) => ({ ...m, [g.key]: g.label }), { other: "Other" });
  const GROUP_KEYS = GROUPS.map((g) => g.key).concat("other");

  const Ic = ({ n }) => <span className="ic-wrap" key={n}><i data-lucide={n} /></span>;

  // ---- One link: show, edit, remove ----------------------------------------
  function ResourceForm({ initial, place, onSaved, onCancel }) {
    const { Button, Input, Select } = DS;
    const [f, setF] = React.useState(() => ({ kind: "case_search", label: "", url: "", notes: "", ...(initial || {}) }));
    const [busy, setBusy] = React.useState(false);
    const [err, setErr] = React.useState(null);
    const set = (k) => (e) => setF((s) => ({ ...s, [k]: e.target.value }));
    async function save() {
      if (!f.label.trim()) { setErr("Give the link a label."); return; }
      setBusy(true); setErr(null);
      try {
        await window.LedgerAPI.saveStateResource({
          resource_id: f.resource_id || null, state: place.state, county: place.county || null,
          kind: f.kind, label: f.label.trim(), url: f.url.trim() || null, notes: f.notes.trim() || null });
        onSaved();
      } catch (e) { setErr(e.message || String(e)); setBusy(false); }
    }
    return (
      <div className="pl-form">
        {err && <div className="login__err" style={{ marginBottom: 10 }}>{err}</div>}
        <div className="form-grid">
          <Select label="Kind" value={f.kind} onChange={set("kind")} options={KINDS.map((k) => ({ value: k, label: KIND_LABEL[k] }))} />
          <Input label="Label *" value={f.label} onChange={set("label")} placeholder="e.g. Superior Court case search" />
          <Input label="Link" value={f.url} onChange={set("url")} placeholder="https://" />
          <Input label="Notes" value={f.notes} onChange={set("notes")} placeholder="Login needed, search by name only…" />
        </div>
        <div className="form-actions">
          <Button variant="ghost" onClick={onCancel} disabled={busy}>Cancel</Button>
          <Button variant="primary" icon="check" onClick={save} disabled={busy}>{busy ? "Saving…" : "Save link"}</Button>
        </div>
      </div>
    );
  }

  function ResourceList({ items, place, inherited, onChanged, onError }) {
    const [editing, setEditing] = React.useState(null); // resource_id | "new"
    React.useEffect(() => { icons(); }, [editing, items]);
    async function remove(r) {
      if (!window.confirm(`Remove “${r.label}”?`)) return;
      try { await window.LedgerAPI.removeStateResource(r.resource_id); onChanged(); }
      catch (e) { onError(e.message || String(e)); }
    }
    const where = place.county ? countyTitle(place.county, place.sample) : stateName(place.state);
    return (
      <div className="pl-res">
        {inherited && inherited.length > 0 && inherited.map((r) => (
          <div key={r.resource_id} className="pl-resrow pl-resrow--inh">
            <Ic n={KIND_ICON[r.kind] || "link"} />
            <div className="pl-resmain">
              {r.url ? <a href={r.url} target="_blank" rel="noreferrer">{r.label}</a> : <b>{r.label}</b>}
              <span className="pl-reskind">{KIND_LABEL[r.kind] || T(r.kind)} · {stateName(r.state)}</span>
              {r.notes && <span className="pl-resnote">{r.notes}</span>}
            </div>
          </div>
        ))}
        {items.map((r) => (editing === r.resource_id ? (
          <ResourceForm key={r.resource_id} initial={{ ...r, url: r.url || "", notes: r.notes || "" }} place={place}
            onCancel={() => setEditing(null)} onSaved={() => { setEditing(null); onChanged(); }} />
        ) : (
          <div key={r.resource_id} className="pl-resrow">
            <Ic n={KIND_ICON[r.kind] || "link"} />
            <div className="pl-resmain">
              {r.url ? <a href={r.url} target="_blank" rel="noreferrer">{r.label}</a> : <b>{r.label}</b>}
              <span className="pl-reskind">{KIND_LABEL[r.kind] || T(r.kind)}{!r.url ? " · no link yet" : ""}</span>
              {r.notes && <span className="pl-resnote">{r.notes}</span>}
            </div>
            <span className="pl-resact">
              <button type="button" className="link-btn" onClick={() => setEditing(r.resource_id)}>Edit</button>
              <button type="button" className="link-btn" onClick={() => remove(r)}>Remove</button>
            </span>
          </div>
        )))}
        {items.length === 0 && !(inherited && inherited.length) && editing !== "new" && (
          <div className="pl-empty">No links for {where} yet: case search, court directory, live streams, FOIA portal.</div>
        )}
        {editing === "new"
          ? <ResourceForm place={place} onCancel={() => setEditing(null)} onSaved={() => { setEditing(null); onChanged(); }} />
          : <button type="button" className="link-btn pl-add" onClick={() => setEditing("new")}><Ic n="plus" /> Add a link for {where}</button>}
      </div>
    );
  }

  // ---- A state's FOIA rule --------------------------------------------------
  function FoiaRule({ state, rule, canEdit, onChanged, compact }) {
    const { Button, Input } = DS;
    const [editing, setEditing] = React.useState(false);
    const [f, setF] = React.useState(null);
    const [busy, setBusy] = React.useState(false);
    const [err, setErr] = React.useState(null);
    React.useEffect(() => { icons(); }, [editing]);
    const start = () => { setF({ residency_required: !!(rule && rule.residency_required), statute_ref: (rule && rule.statute_ref) || "", notes: (rule && rule.notes) || "" }); setErr(null); setEditing(true); };
    async function save() {
      setBusy(true); setErr(null);
      try { await window.LedgerAPI.saveStateFoiaRule({ state, ...f }); setEditing(false); onChanged(); }
      catch (e) { setErr(e.message || String(e)); }
      finally { setBusy(false); }
    }
    if (editing) {
      return (
        <div className="pl-form">
          {err && <div className="login__err" style={{ marginBottom: 10 }}>{err}</div>}
          <label className="pl-check"><input type="checkbox" checked={f.residency_required}
            onChange={(e) => setF((s) => ({ ...s, residency_required: e.target.checked }))} /> Only residents can file (we use an outside requester)</label>
          <div className="form-grid">
            <Input label="Statute" value={f.statute_ref} onChange={(e) => setF((s) => ({ ...s, statute_ref: e.target.value }))} placeholder="e.g. Ga. Code § 50-18-70" />
            <div className="full">
              <label className="field-label">Rules and notes</label>
              <textarea className="lc-input ledger-textarea" value={f.notes} onChange={(e) => setF((s) => ({ ...s, notes: e.target.value }))}
                placeholder="e.g. Bodycam released 60 days after adjudication." />
            </div>
          </div>
          <div className="form-actions">
            <Button variant="ghost" onClick={() => setEditing(false)} disabled={busy}>Cancel</Button>
            <Button variant="primary" icon="check" onClick={save} disabled={busy}>{busy ? "Saving…" : "Save rule"}</Button>
          </div>
        </div>
      );
    }
    return (
      <div className={"pl-rule" + (compact ? " pl-rule--compact" : "")}>
        {rule ? (
          <>
            <div className="pl-rulehead">
              {rule.residency_required
                ? <span className="chip pl-chip--warn">Residents only: file via an outside requester</span>
                : <span className="chip">Anyone can file</span>}
              {rule.statute_ref && <span className="pl-reskind">{rule.statute_ref}</span>}
            </div>
            {rule.notes && <div className="pl-rulenotes">{rule.notes}</div>}
          </>
        ) : <div className="pl-empty">No FOIA rule recorded for {stateName(state)}.</div>}
        {canEdit && !compact && <button type="button" className="link-btn pl-add" onClick={start}><Ic n="pencil" /> {rule ? "Edit rule" : "Add a rule"}</button>}
      </div>
    );
  }

  // ---- One agency card in a county or a state -------------------------------
  function AgencyCard({ a, onOpen }) {
    React.useEffect(() => { icons(); }, []);
    // G3: the primary contact by role ("PIO · Mike Moore · 813…"); legacy columns if the directory had no role.
    const pc = a.primary_contact;
    const contact = pc ? [pc.name, pc.phone, pc.email].filter(Boolean) : [a.contact_name, a.phone, a.email].filter(Boolean);
    const quirks = window.agencyQuirkChips ? window.agencyQuirkChips(a) : [];
    return (
      <div className="ag-card pl-card">
        <div className="ag-name"><button type="button" className="ag-namelink" onClick={() => onOpen(a.entity_id)}>{a.entity_name}</button></div>
        <div className="ag-meta">
          <span className="ag-loc">{[a.entity_type && T(a.entity_type), a.city].filter(Boolean).join(" · ") || "—"}</span>
          {a.foia_method && <span className="chip">{window.vocabLabel ? window.vocabLabel("foia_method", a.foia_method) : T(a.foia_method)}</span>}
          {quirks.map((q) => <span key={q.k} className={"chip" + (q.warn ? " pl-chip--warn" : "")}>{q.text}</span>)}
        </div>
        {(contact.length > 0 || a.website) && (
          <div className="ag-contact" style={{ marginTop: 8 }}>
            {contact.length > 0 && <span><i data-lucide="user" /> {pc && <span className="ag-rolemini">{window.agencyRoleLabel(pc.role)}</span>}{contact.join(" · ")}</span>}
            {a.website && <span><i data-lucide="globe" /> <a href={a.website} target="_blank" rel="noreferrer">{String(a.website).replace(/^https?:\/\//, "").replace(/\/$/, "")}</a></span>}
          </div>
        )}
        <div className="pl-counts">{a.foia_count || 0} request{a.foia_count === 1 ? "" : "s"} · {a.matter_count || 0} matter{a.matter_count === 1 ? "" : "s"}</div>
      </div>
    );
  }

  // `after` renders below one group (G4: the county's courthouses below its courts, even when
  // no court is on file yet).
  function Grouped({ rows, onOpen, after = {} }) {
    const by = {};
    rows.forEach((a) => { (by[groupOf(a.entity_type)] || (by[groupOf(a.entity_type)] = [])).push(a); });
    return GROUP_KEYS.filter((k) => by[k] || after[k]).map((k) => (
      <React.Fragment key={k}>
        {by[k] && (
          <div className="pl-sec">
            <div className="form-subhead">{GROUP_LABEL[k]} ({by[k].length})</div>
            <div className="ag-grid">
              {by[k].sort((x, y) => (y.foia_count || 0) - (x.foia_count || 0) || x.entity_name.localeCompare(y.entity_name))
                .map((a) => <AgencyCard key={a.entity_id} a={a} onOpen={onOpen} />)}
            </div>
          </div>
        )}
        {after[k] || null}
      </React.Fragment>
    ));
  }

  // ---- The view -------------------------------------------------------------
  function LocationView({ rows, place, setPlace, onOpenAgency, onOpenCourthouse, onShowUnplaced }) {
    const [res, setRes] = React.useState(null);
    const [rules, setRules] = React.useState(null);
    const [err, setErr] = React.useState(null);       // load failed: nothing to show
    const [actErr, setActErr] = React.useState(null); // one action refused: say so, keep the page
    React.useEffect(() => { setActErr(null); }, [place]);
    const canEditRules = !!(window.LedgerCaps && (window.LedgerCaps.isContentOps || window.LedgerCaps.isAdmin));
    const load = React.useCallback(() => {
      Promise.all([window.LedgerAPI.listStateResources(), window.LedgerAPI.listStateFoiaRules()])
        .then(([r, f]) => { setRes(r); setRules(f); }).catch((e) => setErr(e.message || String(e)));
    }, []);
    React.useEffect(() => { load(); }, [load]);
    React.useEffect(() => { icons(); }, [place, res, rows]);

    if (err) return <div className="login__err">{err}</div>;
    if (!res || !rules) return <div style={{ color: "var(--text-muted)", fontSize: 13 }}>Loading…</div>;

    const ruleOf = (s) => rules.find((r) => r.state === s) || null;
    const actBanner = actErr && <div className="login__err" style={{ marginBottom: 14 }}>{actErr}</div>;
    const inState = (s) => rows.filter((a) => a.state === s);
    const lc = (s) => String(s || "").toLowerCase();

    // ---- one county ----
    if (place.state && place.county) {
      const here = inState(place.state).filter((a) => lc(a.county) === lc(place.county));
      const sample = here[0];
      const statewide = res.filter((r) => r.state === place.state && !r.county);
      const own = res.filter((r) => r.state === place.state && lc(r.county) === lc(place.county));
      return (
        <div>
          <div className="pl-crumbs">
            <button type="button" className="link-btn" onClick={() => setPlace({})}>All states</button> ›{" "}
            <button type="button" className="link-btn" onClick={() => setPlace({ state: place.state })}>{stateName(place.state)}</button>
          </div>
          <h2 className="pl-title">{countyTitle(place.county, sample)}, {place.state}<window.LedgerComment section="Agencies county panel" /></h2>
          {actBanner}
          <div className="pl-two">
            <DS.Card><DS.Card.Body>
              <div className="form-subhead">Links</div>
              <ResourceList items={own} inherited={statewide} place={{ ...place, sample }} onChanged={() => { setActErr(null); load(); }} onError={setActErr} />
            </DS.Card.Body></DS.Card>
            <DS.Card><DS.Card.Body>
              <div className="form-subhead">{stateName(place.state)} FOIA rule</div>
              <FoiaRule state={place.state} rule={ruleOf(place.state)} canEdit={false} compact onChanged={load} />
            </DS.Card.Body></DS.Card>
          </div>
          {/* G4: courthouses (Content Ops only, D12) sit under the courts. */}
          {here.length === 0 && <div className="ledger-empty"><i data-lucide="building-2" /><b>No agencies in {countyTitle(place.county, sample)} yet</b></div>}
          <Grouped rows={here} onOpen={onOpenAgency}
            after={window.LedgerCourthouses && window.LedgerCourthouses.canUse() && onOpenCourthouse
              ? { court: <window.LedgerCourthouses.Section state={place.state} county={place.county} onOpen={onOpenCourthouse} /> } : {}} />
        </div>
      );
    }

    // ---- one state ----
    if (place.state) {
      const all = inState(place.state);
      const statewideAg = all.filter((a) => !a.county && a.scope && a.scope !== "local");
      const unplaced = all.filter(window.agencyUnplaced);
      const counties = {};
      all.filter((a) => a.county).forEach((a) => {
        const k = lc(a.county);
        const c = counties[k] || (counties[k] = { name: a.county, sample: a, n: 0, req: 0, g: {} });
        c.n += 1; c.req += a.foia_count || 0;
        const g = groupOf(a.entity_type); c.g[g] = (c.g[g] || 0) + 1;
      });
      const countyList = Object.values(counties).sort((x, y) => x.name.localeCompare(y.name));
      const own = res.filter((r) => r.state === place.state && !r.county);
      return (
        <div>
          <div className="pl-crumbs"><button type="button" className="link-btn" onClick={() => setPlace({})}>All states</button></div>
          <h2 className="pl-title">{stateName(place.state)}<window.LedgerComment section="Agencies state page" /></h2>
          {actBanner}
          <div className="pl-two">
            <DS.Card><DS.Card.Body>
              <div className="form-subhead">Statewide links</div>
              <ResourceList items={own} place={place} onChanged={() => { setActErr(null); load(); }} onError={setActErr} />
            </DS.Card.Body></DS.Card>
            <DS.Card><DS.Card.Body>
              <div className="form-subhead">FOIA rule</div>
              <FoiaRule state={place.state} rule={ruleOf(place.state)} canEdit={canEditRules} onChanged={load} />
            </DS.Card.Body></DS.Card>
          </div>

          <div className="form-subhead">Counties ({countyList.length})</div>
          {countyList.length === 0
            ? <div className="pl-empty" style={{ marginBottom: 20 }}>No agency in {stateName(place.state)} has a county yet.</div>
            : (
              <DS.Card style={{ marginBottom: 22 }}><DS.Card.Body style={{ padding: 0 }}>
                <table className="tbl">
                  <thead><tr><th>County</th><th>Courts</th><th>Sheriff and police</th><th>Prosecutor</th><th>Other</th><th>Requests</th></tr></thead>
                  <tbody>
                    {countyList.map((c) => (
                      <tr key={c.name} onClick={() => setPlace({ state: place.state, county: c.name })}>
                        <td className="cname">{countyTitle(c.name, c.sample)}</td>
                        {GROUP_KEYS.map((k) => <td key={k} className="cdef" style={{ fontVariantNumeric: "tabular-nums" }}>{c.g[k] || "—"}</td>)}
                        <td className="cdef" style={{ fontVariantNumeric: "tabular-nums" }}>{c.req || "—"}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </DS.Card.Body></DS.Card>
            )}

          {statewideAg.length > 0 && (
            <div className="pl-sec">
              <div className="form-subhead">Statewide and federal agencies ({statewideAg.length})</div>
              <div className="ag-grid">{statewideAg.map((a) => <AgencyCard key={a.entity_id} a={a} onOpen={onOpenAgency} />)}</div>
            </div>
          )}
          {unplaced.length > 0 && (
            <div className="pl-unplaced">
              <Ic n="map-pin-off" /> {unplaced.length} agenc{unplaced.length === 1 ? "y" : "ies"} in {stateName(place.state)} not placed in a county yet.{" "}
              <button type="button" className="link-btn" onClick={() => onShowUnplaced(place.state)}>Show them</button>
            </div>
          )}
        </div>
      );
    }

    // ---- every state ----
    const states = {};
    rows.filter((a) => a.state).forEach((a) => {
      const s = states[a.state] || (states[a.state] = { state: a.state, n: 0, counties: new Set(), unplaced: 0 });
      s.n += 1;
      if (a.county) s.counties.add(lc(a.county)); else if (window.agencyUnplaced(a)) s.unplaced += 1;
    });
    res.forEach((r) => { if (!states[r.state]) states[r.state] = { state: r.state, n: 0, counties: new Set(), unplaced: 0 }; });
    const list = Object.values(states).sort((x, y) => stateName(x.state).localeCompare(stateName(y.state)));
    const links = (s) => res.filter((r) => r.state === s).length;
    return (
      <div className="pl-states">
        {list.map((s) => (
          <button type="button" key={s.state} className="pl-tile" onClick={() => setPlace({ state: s.state })}>
            <span className="pl-tilecode">{s.state}</span>
            <span className="pl-tilename">{stateName(s.state)}</span>
            <span className="pl-tilemeta">
              {s.n} agenc{s.n === 1 ? "y" : "ies"} · {s.counties.size} count{s.counties.size === 1 ? "y" : "ies"}
              {links(s.state) ? ` · ${links(s.state)} link${links(s.state) === 1 ? "" : "s"}` : ""}
              {ruleOf(s.state) && ruleOf(s.state).residency_required ? " · residents only" : ""}
            </span>
          </button>
        ))}
      </div>
    );
  }

  window.LedgerAgencyPlaces = { LocationView, KIND_LABEL };
})();
