/* === Comms schedule upload (admin) ===
   Comms' project-management tool exports a task list per product (Task Name /
   Status / Planned Start / Planned Completion / Actual Completion /
   Approvals). Drop one or MORE exports here, link each to its tracked work
   item, and choose what to apply. Nothing is written silently: the publish
   target and status are one-click adoptions (same philosophy as the
   milestone "Use N" button), and the full plan is stored on the work item
   (w.commsPlan) so the panel can show where the product sits in Comms'
   pipeline. Re-upload a refreshed export any time — the card shows the slip
   against what's stored. The product name lives only in the export's
   FILENAME, so each card offers a fuzzy-matched work-item guess to confirm. */

function cuParse(rawText, fileName) {
  const rows = parseCsvText(rawText);
  if (!rows.length) return null;
  const header = rows[0].map((x) => x.trim());
  const col = (n) => header.indexOf(n);
  if (col("Task Name") < 0 || col("Planned Completion Date") < 0) return null;
  const tasks = rows.slice(1)
    .filter((r) => r.length >= 3 && (r[col("Task Name")] || "").trim())
    .map((r) => {
      const get = (n) => (r[col(n)] || "").trim();
      return {
        name: get("Task Name"), status: get("Status"),
        plannedStart: get("Planned Start Date"), plannedEnd: get("Planned Completion Date"),
        actualEnd: get("Actual Completion Date"), approvals: get("Approvals"),
      };
    });
  if (!tasks.length) return null;

  const parseD = (s) => { const d = new Date(s); return isNaN(d) ? null : d; };
  const fmt = (d) => d ? d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : null;
  // "Done" trusts the Actual Completion Date first; status text is a loose
  // backup (the pre-kickoff sample only shows "New" — vocabulary TBD).
  const isDone = (t) => !!t.actualEnd || /complete|done|closed/i.test(t.status);
  const target = tasks.reduce((mx, t) => { const d = parseD(t.plannedEnd); return d && (!mx || d > mx) ? d : mx; }, null);
  const start = tasks.reduce((mn, t) => { const d = parseD(t.plannedStart); return d && (!mn || d < mn) ? d : mn; }, null);
  const lastActual = tasks.reduce((mx, t) => { const d = parseD(t.actualEnd); return d && (!mx || d > mx) ? d : mx; }, null);
  const done = tasks.filter(isDone).length;
  const firstOpen = tasks.find((t) => !isDone(t));
  return {
    source: fileName,
    updated: new Date().toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }),
    titleHint: fileName.replace(/_?Exported_Tasks.*$/i, "").replace(/\.csv$/i, "").replace(/_+/g, " ").trim(),
    tasks, total: tasks.length, done,
    target: fmt(target), start: fmt(start),
    completedOn: done === tasks.length ? fmt(lastActual) : null,
    currentPhase: done === 0 ? "not started" : (firstOpen ? firstOpen.name : "all tasks complete"),
  };
}

/* Best-overlap work item for a filename-derived title hint (a guess to
   confirm, never auto-applied). */
function cuGuessWork(titleHint) {
  const words = titleHint.toLowerCase().split(/\s+/).filter((x) => x.length > 3);
  let best = null, bestScore = 0;
  for (const w of window.WORK_ITEMS || []) {
    const t = w.title.toLowerCase();
    const score = words.filter((x) => t.includes(x)).length;
    if (score > bestScore) { best = w; bestScore = score; }
  }
  return bestScore >= 2 ? best.id : "";
}

function CommsUpload({ onClose }) {
  const [cards, setCards] = React.useState([]);
  const [err, setErr] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [done, setDone] = React.useState(null);

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

  function handleFiles(e) {
    setErr(null); setDone(null);
    for (const f of [...e.target.files]) {
      const reader = new FileReader();
      reader.onload = () => {
        try {
          const plan = cuParse(String(reader.result).replace(/^﻿/, ""), f.name);
          if (!plan) { setErr(`"${f.name}" doesn't look like a Comms task export (needs Task Name + Planned Completion Date columns).`); return; }
          setCards((prev) => {
            if (prev.some((c) => c.plan.source === f.name)) return prev;
            const workId = cuGuessWork(plan.titleHint);
            return [...prev, { plan, workId, applyDue: true, applyStatus: plan.done > 0, applyCompleted: !!plan.completedOn }];
          });
        } catch (ex) { setErr(`${f.name}: ${String(ex.message || ex)}`); }
      };
      reader.readAsText(f, "utf-8");
    }
    e.target.value = "";
  }

  const setCard = (i, patch) => setCards(cards.map((c, x) => x === i ? { ...c, ...patch } : c));
  const linked = cards.filter((c) => c.workId);

  async function commit() {
    setBusy(true); setErr(null);
    try {
      const events = linked.map((c) => {
        const w = (window.WORK_ITEMS || []).find((x) => x.id === c.workId);
        const statusText = `with Comms — ${c.plan.currentPhase}`.slice(0, 80);
        const patch = { commsPlan: c.plan };
        const prev = { commsPlan: w.commsPlan || null };
        if (c.applyDue && c.plan.target) {
          patch.due = c.plan.target; patch.firmness = "quoted";   // dates from a real plan
          prev.due = w.due || null; prev.firmness = w.firmness || null;
        }
        if (c.applyStatus && !c.applyCompleted) { patch.status = statusText; prev.status = w.status || null; }
        if (c.applyCompleted && c.plan.completedOn) { patch.completedDate = c.plan.completedOn; prev.completedDate = w.completedDate || null; }
        return { entityType: "work", entityId: c.workId, action: "update", patch, prev, note: "Comms schedule sync" };
      });
      events.push({ entityType: "meta", entityId: "app", action: "update",
        patch: { lastCommsUpload: new Date().toISOString() },
        prev: { lastCommsUpload: (window.META && window.META.lastCommsUpload) || null } });
      for (let i = 0; i < events.length; i += 40) await window.Store.commit(events.slice(i, i + 40));
      setDone(`Applied ${linked.length} schedule(s).`);
      setCards([]);
    } catch (ex) { setErr(String(ex.message || ex)); }
    finally { setBusy(false); }
  }

  const input = {
    width: "100%", padding: "5px 8px", borderRadius: 4, border: "1px solid var(--border)",
    background: "var(--surface-2)", font: "500 12px/1.3 var(--sans)", outline: "none",
  };

  return (
    <>
      <div className="scrim is-open" onClick={onClose}></div>
      <aside className="side-panel is-open" style={{ width: 680 }}>
        <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">Comms sync</div>
          <div className="side-panel__title" style={{ fontSize: 19 }}>Import Comms schedules</div>
        </div>

        <div className="side-panel__section">
          <div className="muted" style={{ fontSize: 12, lineHeight: 1.6, marginBottom: 10 }}>
            Drop one or more Comms task exports (CSV). Link each to its work item, choose what to apply —
            publish target as the due date, current phase as the status — and sync. The full plan lands on
            the work item's panel; re-upload a refreshed export any time to see and adopt slips.
          </div>
          <input type="file" accept=".csv" multiple onChange={handleFiles}
            style={{ fontSize: 12, fontFamily: "var(--mono)" }} />
        </div>

        {cards.map((c, i) => {
          const w = (window.WORK_ITEMS || []).find((x) => x.id === c.workId);
          const slip = w && w.commsPlan && w.commsPlan.target && c.plan.target && w.commsPlan.target !== c.plan.target;
          return (
            <div key={c.plan.source} className="side-panel__section">
              <h4 style={{ overflowWrap: "anywhere" }}>{c.plan.titleHint || c.plan.source}</h4>
              <div className="muted" style={{ fontSize: 11, lineHeight: 1.6, marginBottom: 8 }}>
                {c.plan.total} tasks · {c.plan.done} done · {c.plan.currentPhase} ·
                publish target <strong style={{ color: "var(--ink-2)" }}>{c.plan.target || "—"}</strong>
                {slip ? <span style={{ color: "var(--accent)", fontWeight: 600 }}> (was {w.commsPlan.target})</span> : null}
              </div>
              <select style={input} value={c.workId} onChange={(e) => setCard(i, { workId: e.target.value })}>
                <option value="">— link to a work item…</option>
                {(window.WORK_ITEMS || []).map((x) => <option key={x.id} value={x.id}>{x.id} — {x.title.slice(0, 60)}</option>)}
              </select>
              {c.workId ? (
                <div style={{ marginTop: 8, display: "flex", flexDirection: "column", gap: 4, fontSize: 12, color: "var(--ink-2)" }}>
                  {c.plan.target ? (
                    <label className="row" style={{ gap: 6, cursor: "pointer", userSelect: "none" }}>
                      <input type="checkbox" checked={c.applyDue} onChange={(e) => setCard(i, { applyDue: e.target.checked })} />
                      Set due date to {c.plan.target} (quoted){w && w.due && w.due !== c.plan.target ? <span className="muted"> — currently {w.due}</span> : null}
                    </label>
                  ) : null}
                  {!c.plan.completedOn ? (
                    <label className="row" style={{ gap: 6, cursor: "pointer", userSelect: "none" }}>
                      <input type="checkbox" checked={c.applyStatus} onChange={(e) => setCard(i, { applyStatus: e.target.checked })} />
                      Set status to "with Comms — {c.plan.currentPhase}"{w && w.status ? <span className="muted"> — currently "{w.status}"</span> : null}
                    </label>
                  ) : (
                    <label className="row" style={{ gap: 6, cursor: "pointer", userSelect: "none" }}>
                      <input type="checkbox" checked={c.applyCompleted} onChange={(e) => setCard(i, { applyCompleted: e.target.checked })} />
                      All tasks complete — mark completed {c.plan.completedOn}
                    </label>
                  )}
                </div>
              ) : null}
            </div>
          );
        })}

        {cards.length ? (
          <div className="side-panel__section" style={{ borderBottom: 0 }}>
            <button className="btn btn--primary" disabled={busy || linked.length === 0} onClick={commit}>
              {busy ? "Applying…" : linked.length === 0 ? "Link at least one work item" : `Apply ${linked.length} schedule(s)`}
            </button>
          </div>
        ) : null}

        {err ? <div style={{ margin: "14px 22px", padding: "8px 12px", borderRadius: 4, background: "var(--red-bg)", color: "var(--red)", fontSize: 12 }}>{err}</div> : null}
        {done ? <div style={{ margin: "14px 22px", padding: "8px 12px", borderRadius: 4, background: "var(--green-bg)", color: "var(--green)", fontSize: 12 }}>{done}</div> : null}
      </aside>
    </>
  );
}

Object.assign(window, { CommsUpload });
