/* === Outreach & Media — external engagement in one place ===
   Three sections: media mentions (manual entry + Google Alert .eml import),
   engagements (conferences / speaking / testimony / travel — manual, owned
   by their creator), and the Salesforce meetings already in the system,
   finally visible across states. Stat tiles use a 30-day window; the bar
   lists rank all tracked mentions. Real-world dates (article date, event
   date) anchor everything, so importing history never reads as news. */

const OUTREACH_TYPES = ["conference", "speaking", "testimony", "travel", "webinar", "other"];
const PUB_TYPES = ["local outlet", "national outlet", "wire service", "trade publication", "newsletter", "blog / Substack", "journal", "TV / radio", "government / press release", "other"];
// Early mentions were stored with the first-draft labels — normalize at read
// time so old records match the current list (no data migration needed).
const PUB_TYPE_LEGACY = { "local paper": "local outlet", "national paper": "national outlet" };
function outPubType(v) { return PUB_TYPE_LEGACY[v] || v; }
const OUT_WINDOW_DAYS = 30;

function outSlugUrl(url) {
  return "mn-" + String(url || "").replace(/^https?:\/\/(www\.)?/, "").toLowerCase()
    .replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 80);
}
function outParseDate(s) {
  if (!s) return null;
  // Bare ISO dates pin to LOCAL midnight (UTC parsing shifts a day back).
  const iso = String(s).match(/^(\d{4})-(\d{2})-(\d{2})$/);
  const d = iso ? new Date(+iso[1], +iso[2] - 1, +iso[3]) : new Date(s);
  return isNaN(d) ? null : d;
}
function outInWindow(dateStr, days = OUT_WINDOW_DAYS) {
  const d = outParseDate(dateStr);
  return d && (Date.now() - d.getTime()) <= days * 864e5 && d.getTime() <= Date.now() + 864e5;
}
function outGeoLabel(state) {
  return !state ? "National" : (window.STATE_NAMES[state] || state);
}

/* ---------- simple count-bar list (house style, no chart lib) ---------- */
function OutBarList({ title, rows, empty }) {
  const max = Math.max(1, ...rows.map((r) => r.n));
  return (
    <div className="card" style={{ padding: 14 }}>
      <div className="eyebrow" style={{ marginBottom: 8 }}>{title}</div>
      {rows.length === 0 ? <div className="muted" style={{ fontSize: 12 }}>{empty || "Nothing tracked yet."}</div> : null}
      {rows.map((r) => (
        <div key={r.label} style={{ display: "grid", gridTemplateColumns: "minmax(0,1fr) 26px", gap: 8, alignItems: "center", padding: "3px 0" }}>
          <div>
            <div style={{ fontSize: 11, color: "var(--ink-2)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{r.label}</div>
            <div style={{ height: 4, background: "var(--surface-3)", borderRadius: 99, marginTop: 2 }}>
              <div style={{ width: `${(r.n / max) * 100}%`, height: "100%", background: "var(--navy)", borderRadius: 99 }}></div>
            </div>
          </div>
          <span className="mono" style={{ fontSize: 11, color: "var(--ink-2)", textAlign: "right" }}>{r.n}</span>
        </div>
      ))}
    </div>
  );
}

function outTally(list, keyFn, limit) {
  const by = {};
  for (const m of list) { const k = keyFn(m); if (k) by[k] = (by[k] || 0) + 1; }
  return Object.entries(by).sort((a, b) => b[1] - a[1]).slice(0, limit)
    .map(([label, n]) => ({ label, n }));
}

/* ---------- forms (reuse the power-map form shell for house style) ---------- */
function MentionForm({ initial, onClose }) {
  const [f, setF] = React.useState(initial || {
    url: "", title: "", summary: "", publication: "", pubType: "",
    state: "", topic: "", quoted: false, who: "", workIds: [], date: "",
  });
  const [busy, setBusy] = React.useState(false);
  const [users, setUsers] = React.useState([]);
  React.useEffect(() => { window.Store.listUsers().then(setUsers).catch(() => setUsers([])); }, []);
  const set = (k, v) => setF({ ...f, [k]: v });

  async function save() {
    if (!f.title.trim() && !f.url.trim()) return;
    setBusy(true);
    const id = initial ? initial.id : (f.url ? outSlugUrl(f.url) : "mn-" + Date.now().toString(36));
    const data = { ...f, id, title: f.title.trim(), url: f.url.trim() };
    await window.Store.commit({
      entityType: "mention", entityId: id,
      action: initial ? "update" : "create",
      patch: data, prev: initial || undefined,
      note: initial ? "mention edited" : "mention added",
    });
    setBusy(false); onClose();
  }

  return (
    <PMFormShell title={initial ? "Edit mention" : "Add media mention"} onSave={save} onClose={onClose} busy={busy}>
      <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 8 }}>
        <PMField label="Article URL">
          <input style={PM_INPUT} value={f.url} autoFocus placeholder="https://…" onChange={(e) => set("url", e.target.value)} />
        </PMField>
        <PMField label="Date">
          <input style={PM_INPUT} type="date" value={f.date} onChange={(e) => set("date", e.target.value)} />
        </PMField>
      </div>
      <PMField label="Headline / title">
        <input style={PM_INPUT} value={f.title} onChange={(e) => set("title", e.target.value)} />
      </PMField>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8 }}>
        <PMField label="Publication">
          <input style={PM_INPUT} value={f.publication} placeholder="e.g. Orange County Breeze" onChange={(e) => set("publication", e.target.value)} />
        </PMField>
        <PMField label="Publication type">
          <select style={PM_INPUT} value={outPubType(f.pubType)} onChange={(e) => set("pubType", e.target.value)}>
            <option value="">— type</option>
            {PUB_TYPES.map((t) => <option key={t} value={t}>{t}</option>)}
          </select>
        </PMField>
        <PMField label="Geography">
          <select style={PM_INPUT} value={f.state} onChange={(e) => set("state", e.target.value)}>
            <option value="">National</option>
            {Object.keys(window.STATE_NAMES).sort().map((a) => <option key={a} value={a}>{a}</option>)}
          </select>
        </PMField>
      </div>
      <PMField label="Topic">
        <input style={PM_INPUT} value={f.topic} placeholder="e.g. CalSavers expansion" onChange={(e) => set("topic", e.target.value)} />
      </PMField>
      <div style={{ display: "grid", gridTemplateColumns: "auto 1fr", gap: 10, alignItems: "center", margin: "0 0 10px" }}>
        <label className="row" style={{ gap: 6, fontSize: 12, color: "var(--ink-2)", cursor: "pointer", userSelect: "none" }}>
          <input type="checkbox" checked={!!f.quoted} onChange={(e) => set("quoted", e.target.checked)} />
          Team member quoted
        </label>
        <input style={PM_INPUT} value={f.who || ""} placeholder="who? (names, comma-separated)" list="out-people"
               onChange={(e) => setF({ ...f, who: e.target.value, quoted: f.quoted || !!e.target.value.trim() })} />
        <datalist id="out-people">
          {users.map((u) => <option key={u.id} value={u.name} />)}
        </datalist>
      </div>
      <PMField label="Linked work products — credit flows to their owners in the Activity snapshot">
        <select style={PM_INPUT} value=""
          onChange={(e) => { if (e.target.value) set("workIds", [...(f.workIds || []), e.target.value]); }}>
          <option value="">+ link a work item…</option>
          {(window.WORK_ITEMS || []).filter((w) => !(f.workIds || []).includes(w.id))
            .map((w) => <option key={w.id} value={w.id}>{w.id} — {w.title.slice(0, 70)}</option>)}
        </select>
        {(f.workIds || []).length ? (
          <div style={{ marginTop: 6, display: "flex", gap: 5, flexWrap: "wrap" }}>
            {f.workIds.map((id) => {
              const w = (window.WORK_ITEMS || []).find((x) => x.id === id);
              return (
                <span key={id} className="chip chip--navy" title={w ? w.title : id} style={{ fontSize: 10 }}>
                  {id}{w && w.owner ? ` · ${w.owner}` : ""}
                  <button style={{ marginLeft: 5, color: "inherit", opacity: 0.7 }} title="unlink"
                    onClick={() => set("workIds", f.workIds.filter((x) => x !== id))}>×</button>
                </span>
              );
            })}
          </div>
        ) : null}
      </PMField>
      <PMField label="Summary">
        <textarea rows={2} style={{ ...PM_INPUT, resize: "vertical" }} value={f.summary} onChange={(e) => set("summary", e.target.value)} />
      </PMField>
    </PMFormShell>
  );
}

function EngagementForm({ initial, onClose }) {
  const me = window.Store.session();
  const [f, setF] = React.useState(initial || {
    type: "conference", title: "", who: "", start: "", end: "", state: "", note: "",
  });
  const [busy, setBusy] = React.useState(false);
  const set = (k, v) => setF({ ...f, [k]: v });

  async function save() {
    if (!f.title.trim()) return;
    setBusy(true);
    const id = initial ? initial.id : "oe-" + Date.now().toString(36);
    const data = { ...f, id, title: f.title.trim(), owner: initial ? initial.owner : (me ? me.name : "?") };
    await window.Store.commit({
      entityType: "outreach", entityId: id,
      action: initial ? "update" : "create",
      patch: data, prev: initial || undefined,
      note: initial ? "engagement edited" : "engagement added",
    });
    setBusy(false); onClose();
  }

  return (
    <PMFormShell title={initial ? "Edit engagement" : "Add engagement"} onSave={save} onClose={onClose} busy={busy}>
      <div style={{ display: "grid", gridTemplateColumns: "130px 1fr", gap: 8 }}>
        <PMField label="Type">
          <select style={PM_INPUT} value={f.type} onChange={(e) => set("type", e.target.value)}>
            {OUTREACH_TYPES.map((t) => <option key={t} value={t}>{t}</option>)}
          </select>
        </PMField>
        <PMField label="Title">
          <input style={PM_INPUT} value={f.title} autoFocus placeholder="e.g. NAST Treasury Management Conference" onChange={(e) => set("title", e.target.value)} />
        </PMField>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 130px 130px 110px", gap: 8 }}>
        <PMField label="Who (comma-separated)">
          <input style={PM_INPUT} value={f.who} placeholder="e.g. John, Kim" onChange={(e) => set("who", e.target.value)} />
        </PMField>
        <PMField label="Start">
          <input style={PM_INPUT} type="date" value={f.start} onChange={(e) => set("start", e.target.value)} />
        </PMField>
        <PMField label="End (optional)">
          <input style={PM_INPUT} type="date" value={f.end} onChange={(e) => set("end", e.target.value)} />
        </PMField>
        <PMField label="Where">
          <select style={PM_INPUT} value={f.state} onChange={(e) => set("state", e.target.value)}>
            <option value="">National</option>
            {Object.keys(window.STATE_NAMES).sort().map((a) => <option key={a} value={a}>{a}</option>)}
          </select>
        </PMField>
      </div>
      <PMField label="Note">
        <textarea rows={2} style={{ ...PM_INPUT, resize: "vertical" }} value={f.note} onChange={(e) => set("note", e.target.value)} />
      </PMField>
    </PMFormShell>
  );
}

/* ---------- section scaffold ---------- */
function OutSection({ title, count, addLabel, onAdd, children }) {
  return (
    <div style={{ marginBottom: 26 }}>
      <div style={{ display: "flex", alignItems: "baseline", gap: 8, margin: "14px 0 8px" }}>
        <span className="eyebrow" style={{ fontSize: 11 }}>{title}</span>
        <span style={{ flex: 1, height: 1, background: "var(--rule)" }}></span>
        {addLabel ? <button className="btn btn--ghost no-print" style={{ fontSize: 11 }} onClick={onAdd}>{addLabel}</button> : null}
        <span className="mono faint" style={{ fontSize: 11 }}>{count}</span>
      </div>
      {children}
    </div>
  );
}

function OutreachView({ onOpenMediaUpload }) {
  const me = window.Store.session();
  const canEdit = me && me.role !== "viewer";
  const isAdmin = me && me.role === "admin";
  const [addingMention, setAddingMention] = React.useState(false);
  const [editMention, setEditMention] = React.useState(null);
  const [addingEng, setAddingEng] = React.useState(false);
  const [editEng, setEditEng] = React.useState(null);

  const mentions = (window.MENTIONS || []).slice()
    .sort((a, b) => (outParseDate(b.date) || 0) - (outParseDate(a.date) || 0));
  const engagements = (window.OUTREACH || []).slice()
    .sort((a, b) => (outParseDate(a.start) || 0) - (outParseDate(b.start) || 0));
  const meetings = (window.MEETINGS || []).slice()
    .sort((a, b) => (outParseDate(b.date) || 0) - (outParseDate(a.date) || 0));

  const now = Date.now();
  const upcoming = engagements.filter((e) => {
    const end = outParseDate(e.end) || outParseDate(e.start);
    return end && end.getTime() >= now - 864e5;
  });
  const past = engagements.filter((e) => !upcoming.includes(e)).reverse();

  const mIn30 = mentions.filter((m) => outInWindow(m.date));
  const quotedIn30 = mIn30.filter((m) => m.quoted);
  const meetIn30 = meetings.filter((m) => outInWindow(m.date));

  // Timeline lane for upcoming engagements (existing smear-bar widget, on a
  // 6-month horizon — outreach rarely plans a year out, and shorter months
  // make short events readable). Bars stay TRUE to the event's span (a
  // 2-day event must not spill into next month), so no text rides inside
  // them — the hover tooltip carries title · type · who · where.
  const tlItems = upcoming.map((e) => {
    const s = dateToMo(e.start), en = dateToMo(e.end || e.start);
    if (s === null) return null;
    const endMo = Math.max(en === null ? s : en, s);
    return { id: e.id, label: e.title, startMo: s, endMo,
             point: endMo - s <= 0.13, // ≤ ~4 days → diamond on the date, not a bar
             firmness: "locked", tag: "",
             tooltip: `${e.title} — ${e.type} · ${e.who || "—"} · ${outGeoLabel(e.state)}` };
  }).filter(Boolean);

  const mentionChip = { fontSize: 10, padding: "1px 7px" };

  return (
    <div>
      <div className="tab-summary">
        <SumStat label={`Mentions (${OUT_WINDOW_DAYS}d)`} value={mIn30.length} accent={mIn30.length ? "green" : null} muted={!mIn30.length} />
        <SumStat label={`Quoted (${OUT_WINDOW_DAYS}d)`} value={quotedIn30.length} muted={!quotedIn30.length} />
        <SumStat label="Engagements upcoming" value={upcoming.length} muted={!upcoming.length} />
        <SumStat label={`Meetings (${OUT_WINDOW_DAYS}d)`} value={meetIn30.length} muted={!meetIn30.length} />
      </div>

      {mentions.length ? (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 14, marginBottom: 10 }}>
          <OutBarList title="Top publications" rows={outTally(mentions, (m) => m.publication, 5)} />
          <OutBarList title="Geography" rows={outTally(mentions, (m) => outGeoLabel(m.state), 6)} />
          <OutBarList title="Publication type" rows={outTally(mentions, (m) => outPubType(m.pubType) || "untyped", 6)} />
        </div>
      ) : null}

      <OutSection title="Media mentions" count={mentions.length}
        addLabel={canEdit ? "+ mention" : null} onAdd={() => { setEditMention(null); setAddingMention(true); }}>
        {isAdmin ? (
          <div className="muted no-print" style={{ fontSize: 11, marginBottom: 8 }}>
            Google Alert emails import in bulk — <a href="#" style={{ color: "var(--accent)", fontWeight: 600 }}
              onClick={(e) => { e.preventDefault(); onOpenMediaUpload && onOpenMediaUpload(); }}>upload saved alert .eml files →</a>
          </div>
        ) : null}
        {(addingMention || editMention) ? (
          <MentionForm initial={editMention} onClose={() => { setAddingMention(false); setEditMention(null); }} />
        ) : null}
        {mentions.length === 0 ? <div className="muted" style={{ fontSize: 12 }}>No mentions tracked yet.</div> : (
          <div className="card">
            {mentions.map((m) => (
              <div key={m.id} className="list-row" style={{ gridTemplateColumns: "86px 1fr auto", alignItems: "start" }}>
                <div>
                  <div className="mono" style={{ fontSize: 11 }}>{m.date ? fmtUsDate(m.date) : "—"}</div>
                  <div className="mono faint" style={{ fontSize: 10, marginTop: 2 }}>{outGeoLabel(m.state)}</div>
                </div>
                <div>
                  <div style={{ fontSize: 13, fontWeight: 500 }}>
                    {m.url ? <a href={m.url} target="_blank" rel="noreferrer" style={{ color: "var(--ink)" }}>{m.title || m.url}</a> : (m.title || "—")}
                  </div>
                  <div style={{ marginTop: 3, display: "flex", gap: 5, flexWrap: "wrap", alignItems: "center" }}>
                    {m.publication ? <span style={{ fontSize: 11, color: "var(--ink-2)", fontWeight: 600 }}>{m.publication}</span> : null}
                    {m.pubType ? <span className="chip" style={mentionChip}>{outPubType(m.pubType)}</span> : null}
                    {m.quoted ? <span className="chip chip--navy" style={mentionChip}>quoted{m.who ? `: ${m.who}` : ""}</span> : null}
                    {(m.workIds || []).map((id) => {
                      const w = (window.WORK_ITEMS || []).find((x) => x.id === id);
                      return <span key={id} className="chip" style={mentionChip} title={w ? `${w.title} — ${w.owner}` : id}>{id}</span>;
                    })}
                    {m.topic ? <span className="muted" style={{ fontSize: 11 }}>· {m.topic}</span> : null}
                  </div>
                  {m.summary ? <div className="muted" style={{ fontSize: 11, marginTop: 3, lineHeight: 1.5 }}>{m.summary}</div> : null}
                </div>
                {canEdit ? (
                  <div className="row no-print" style={{ gap: 6 }}>
                    <button className="btn btn--ghost" style={{ fontSize: 10 }} onClick={() => { setAddingMention(false); setEditMention(m); }}>edit</button>
                    <button className="btn btn--ghost" style={{ fontSize: 10, color: "var(--red)" }}
                      onClick={() => window.Store.commit({ entityType: "mention", entityId: m.id, action: "delete", prev: { title: m.title }, note: "mention removed" })}>remove</button>
                  </div>
                ) : null}
              </div>
            ))}
          </div>
        )}
      </OutSection>

      <OutSection title="Engagements — conferences · speaking · testimony · travel" count={engagements.length}
        addLabel={canEdit ? "+ engagement" : null} onAdd={() => { setEditEng(null); setAddingEng(true); }}>
        {(addingEng || editEng) ? (
          <EngagementForm initial={editEng} onClose={() => { setAddingEng(false); setEditEng(null); }} />
        ) : null}
        {tlItems.length ? (
          <div style={{ marginBottom: 14 }}>
            <FirmnessTimeline fuzziness="subtle" title="Upcoming engagements"
              sub="The bar spans the event — hover for who's going and where."
              items={tlItems} months={6} legend={false} itemsLabel="Engagements" />
          </div>
        ) : null}
        {engagements.length === 0 ? <div className="muted" style={{ fontSize: 12 }}>Nothing tracked yet — conferences, speaking events, testimony, travel.</div> : (
          <div className="card">
            {[...upcoming, ...past].map((e) => {
              const mine = me && (e.owner === me.name || isAdmin);
              const isPast = past.includes(e);
              return (
                <div key={e.id} className="list-row" style={{ gridTemplateColumns: "120px 1fr auto", alignItems: "start", opacity: isPast ? 0.65 : 1 }}>
                  <div>
                    <div className="mono" style={{ fontSize: 11, whiteSpace: "nowrap" }}>{e.start ? fmtUsDate(e.start) : "TBD"}{e.end && e.end !== e.start ? " –" : ""}</div>
                    {e.end && e.end !== e.start ? (
                      <div className="mono" style={{ fontSize: 11, whiteSpace: "nowrap" }}>{fmtUsDate(e.end)}</div>
                    ) : null}
                    <div className="mono faint" style={{ fontSize: 10, marginTop: 2, textTransform: "uppercase", letterSpacing: ".08em" }}>{e.type}</div>
                  </div>
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 500 }}>{e.title}</div>
                    <div className="muted" style={{ fontSize: 11, marginTop: 2 }}>
                      {e.who ? <>{e.who} · </> : null}{outGeoLabel(e.state)}{e.note ? <> — {e.note}</> : null}
                    </div>
                  </div>
                  {mine ? (
                    <div className="row no-print" style={{ gap: 6 }}>
                      <button className="btn btn--ghost" style={{ fontSize: 10 }} onClick={() => { setAddingEng(false); setEditEng(e); }}>edit</button>
                      <button className="btn btn--ghost" style={{ fontSize: 10, color: "var(--red)" }}
                        onClick={() => window.Store.commit({ entityType: "outreach", entityId: e.id, action: "delete", prev: { title: e.title }, note: "engagement removed" })}>remove</button>
                    </div>
                  ) : null}
                </div>
              );
            })}
          </div>
        )}
      </OutSection>

      <OutSection title="Meetings — from Salesforce" count={meetings.length}>
        {meetings.length === 0 ? (
          <div className="muted" style={{ fontSize: 12 }}>No meetings synced yet — they arrive via the Salesforce upload (sidebar).</div>
        ) : (
          <div className="card">
            {meetings.map((m) => (
              <div key={m.id} className="list-row" style={{ gridTemplateColumns: "86px 1fr auto" }}>
                <span className="mono" style={{ fontSize: 11 }}>{m.date}</span>
                <span style={{ fontSize: 12 }}>
                  <strong>{m.contact}</strong> <span className="muted">· {m.assigned}</span>
                  <span className="muted" style={{ display: "block", fontSize: 11 }}>{m.subject}</span>
                </span>
                <span className="mono faint" style={{ fontSize: 11 }}>{outGeoLabel(m.state)}</span>
              </div>
            ))}
          </div>
        )}
      </OutSection>
    </div>
  );
}

Object.assign(window, { OutreachView, outSlugUrl, PUB_TYPES, outPubType });
