// SQSEO Content plan (Phase 11). A 30-day publishing calendar built from real
// state only: saved briefs (with their user-set editorial status), the highest-
// opportunity keywords that don't have a brief yet, and the cadence preference
// from onboarding. Live: GET /api/calendar; actions PATCH /api/briefs/:id/plan
// (schedule / mark published — publishing is always a user action, never faked)
// and PATCH /api/onboarding/wizard (cadence).
(function init(){
if(!window.LongtailIQDesignSystem_ae8f12 || !window.LTQ || !window.LTQ.useApi || !window.LTQ.Popover || !window.LTQ.Modal || !window.LTQ.BriefDrawer){return setTimeout(init,30);}
const React = window.React;
const DS = window.LongtailIQDesignSystem_ae8f12;
const { Card, Icon, Button } = DS;
const { useApi, api, toast, SectionTitle, EmptyState, Popover, MenuItem, Modal, BriefDrawer, SavedBriefDrawer } = window.LTQ;
const t = (k, v) => (window.LTQ.t ? window.LTQ.t(k, v) : k);

// Entry status → chip treatment. "Published" is user-marked; "suggested" is an
// explicit suggestion (no brief yet) — the chip vocabulary keeps that honest.
const STATUS = {
  published: { key: "calendar.published", color: "var(--viz-green)", icon: "check", solid: true },
  scheduled: { key: "calendar.scheduled", color: "var(--accent-500)", icon: "calendar-check" },
  ready: { key: "calendar.ready", color: "var(--viz-blue)", icon: "file-pen-line" },
  suggested: { key: "calendar.suggested", color: "var(--text-faint)", icon: "sparkles", dashed: true },
};
const CADENCES = ["daily", "3x_week", "weekly", "biweekly", "manual"];
const cadenceLabel = (id) => (CADENCES.includes(id) ? t("wizard.cadence." + id) : id);

const DAY_MS = 86400000;
const toUtc = (iso) => { const [y, m, d] = iso.split("-").map(Number); return Date.UTC(y, m - 1, d); };
const toIso = (ms) => new Date(ms).toISOString().slice(0, 10);
const todayIso = () => new Date().toISOString().slice(0, 10);
const fmtDay = (iso) => (window.LTQ.fmtDate ? window.LTQ.fmtDate(new Date(toUtc(iso)), { month: "short", day: "numeric", timeZone: "UTC" }) : iso);

// Build the week rows the grid renders: from the Monday of the start week to
// the Sunday after the window, flagging days outside [start, start+days).
function weekRows(start, days){
  const s = toUtc(start);
  const dow = new Date(s).getUTCDay(); // 0 Sun .. 6 Sat
  const gridStart = s - ((dow + 6) % 7) * DAY_MS; // back to Monday
  const endExcl = s + days * DAY_MS;
  const weeks = [];
  for (let w = gridStart; w < endExcl; w += 7 * DAY_MS) {
    const row = [];
    for (let i = 0; i < 7; i++) {
      const ms = w + i * DAY_MS;
      row.push({ iso: toIso(ms), inWindow: ms >= s && ms < endExcl });
    }
    weeks.push(row);
  }
  return weeks;
}

function LegendDot({ s }) {
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 11.5, fontWeight: 600, color: "var(--text-muted)" }}>
      <span style={{ width: 7, height: 7, borderRadius: 999, background: s.color, border: s.dashed ? "1px dashed var(--border-strong)" : "none", ...(s.dashed ? { background: "var(--paper)" } : {}) }} />
      {t(s.key)}
    </span>
  );
}

function StripStat({ label, value, icon, tone, loading }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 11, minWidth: 0 }}>
      <span style={{ width: 34, height: 34, borderRadius: 10, flex: "none", display: "grid", placeItems: "center", background: "var(--ink-50)", border: "1px solid var(--border-subtle)" }}>
        <Icon name={icon} size={16} style={{ color: tone || "var(--text-faint)" }} />
      </span>
      <div style={{ minWidth: 0 }}>
        {loading ? <span className="lt-shimmer" style={{ display: "block", height: 18, width: 34, borderRadius: 5, background: "var(--ink-100)" }} />
          : <div className="lt-num" style={{ fontFamily: "var(--font-mono)", fontSize: 19, fontWeight: 700, color: "var(--text-strong)", lineHeight: 1.1 }}>{value}</div>}
        <div style={{ fontSize: 11.5, color: "var(--text-muted)", fontWeight: 600, whiteSpace: "nowrap" }}>{label}</div>
      </div>
    </div>
  );
}

// The publishing-status strip: honest counts + the cadence control + live dot.
function PlanStrip({ plan, loading, onCadence, savingCadence }) {
  const s = (plan && plan.summary) || {};
  return (
    <Card pad={0}>
      <div style={{ display: "flex", alignItems: "center", gap: 22, padding: "14px 18px", flexWrap: "wrap" }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 8, flex: "none" }}>
          <span style={{ position: "relative", width: 9, height: 9, flex: "none" }}>
            <span className="fx-pulse-wave" style={{ position: "absolute", inset: 0, borderRadius: 999, background: "var(--viz-green)", opacity: 0.35 }} />
            <span style={{ position: "absolute", inset: 1.5, borderRadius: 999, background: "var(--viz-green)" }} />
          </span>
          <span style={{ fontSize: 12.5, fontWeight: 700, color: "var(--text-strong)", whiteSpace: "nowrap" }}>{t("calendar.plan_live")}</span>
        </span>
        <StripStat label={t("calendar.published")} value={s.published || 0} icon="badge-check" tone="var(--viz-green)" loading={loading} />
        <StripStat label={t("calendar.on_calendar")} value={s.scheduled || 0} icon="calendar-check" tone="var(--accent-500)" loading={loading} />
        <StripStat label={t("dash.briefs_ready")} value={s.ready || 0} icon="file-pen-line" tone="var(--viz-blue)" loading={loading} />
        <StripStat label={t("calendar.suggested_next")} value={s.suggested || 0} icon="sparkles" loading={loading} />
        <span style={{ flex: 1 }} />
        <Popover align="right" width={230} trigger={(open, toggle) => (
          <button onClick={toggle} disabled={savingCadence} style={{ display: "inline-flex", alignItems: "center", gap: 8, height: 32, padding: "0 12px", borderRadius: 8, border: "1px solid var(--border-subtle)", background: "var(--paper)", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 12.5, fontWeight: 600, color: "var(--text-body)" }}>
            <Icon name="calendar-clock" size={14} style={{ color: "var(--text-faint)" }} />
            {savingCadence ? t("calendar.saving") : cadenceLabel(plan ? plan.cadence : "weekly")}
            <Icon name="chevron-down" size={13} style={{ color: "var(--text-faint)" }} />
          </button>
        )}>
          {(close) => (
            <>
              <div style={{ fontSize: 11, fontWeight: 600, color: "var(--text-faint)", letterSpacing: "0.02em", padding: "4px 9px 6px" }}>{t("calendar.publish_cadence")}</div>
              {CADENCES.map((c) => (
                <MenuItem key={c} icon="calendar-clock" label={t("wizard.cadence." + c)} sub={t("calendar.cadence_sub_" + c)} active={plan && plan.cadence === c}
                  trailing={plan && plan.cadence === c ? <Icon name="check" size={14} style={{ color: "var(--accent-500)", flex: "none" }} /> : null}
                  onClick={() => { close(); onCadence(c); }} />
              ))}
            </>
          )}
        </Popover>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 14, padding: "9px 18px", borderTop: "1px solid var(--border-subtle)", flexWrap: "wrap" }}>
        {["published", "scheduled", "ready", "suggested"].map((k) => <LegendDot key={k} s={STATUS[k]} />)}
        <span style={{ fontSize: 11.5, color: "var(--text-faint)" }}>{t("calendar.honest_note")}</span>
      </div>
    </Card>
  );
}

function EntryChip({ entry, onOpen }) {
  const s = STATUS[entry.status] || STATUS.suggested;
  const [hover, setHover] = React.useState(false);
  return (
    <button onClick={() => onOpen(entry)} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      title={entry.keyword + " · " + t(s.key)}
      style={{ display: "flex", alignItems: "center", gap: 6, width: "100%", padding: "4px 7px", borderRadius: 7,
        border: s.dashed ? "1px dashed var(--border-strong)" : "1px solid var(--border-subtle)",
        background: s.solid ? "var(--accent-50, #ecfdf5)" : hover ? "var(--ink-50)" : "var(--paper)",
        cursor: "pointer", textAlign: "left", transition: "background var(--dur-fast) var(--ease-out)" }}>
      <Icon name={s.icon} size={11} style={{ color: s.color, flex: "none" }} />
      <span style={{ flex: 1, minWidth: 0, fontFamily: "var(--font-sans)", fontSize: 11.5, fontWeight: 600, color: "var(--text-strong)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{entry.keyword}</span>
    </button>
  );
}

// Detail modal for one plan entry: status, schedule, and the brief actions.
function EntryModal({ entry, onClose, onOpenBrief, onChanged }) {
  const s = STATUS[entry.status] || STATUS.suggested;
  const [date, setDate] = React.useState(entry.date);
  const [busy, setBusy] = React.useState(false);
  const patch = async (body, msg) => {
    setBusy(true);
    const r = await api.patch("/api/briefs/" + entry.briefId + "/plan", body);
    setBusy(false);
    if (r.ok) { toast(msg, { tone: "success" }); onChanged(); onClose(); }
    else toast(r.error || t("calendar.update_failed"), { tone: "error" });
  };
  const isBrief = !!entry.briefId;
  const published = entry.status === "published";
  return (
    <Modal title={entry.keyword} sub={t(s.key) + " · " + fmtDay(entry.date) + (entry.cluster ? " · " + entry.cluster : "")} onClose={onClose} width={430}>
      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        <Button variant="secondary" leadingIcon={isBrief ? "file-text" : "sparkles"} onClick={() => { onClose(); onOpenBrief(entry); }}>
          {isBrief ? t("calendar.open_brief") : t("calendar.generate_brief")}
        </Button>
        {isBrief && (
          <>
            <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
              <input type="date" value={date} onChange={(e) => setDate(e.target.value)} aria-label={t("calendar.scheduled_date")}
                style={{ flex: 1, height: 38, padding: "0 10px", borderRadius: 9, border: "1px solid var(--border-subtle)", background: "var(--paper)", fontFamily: "var(--font-mono)", fontSize: 12.5, color: "var(--text-strong)" }} />
              <Button variant="secondary" leadingIcon="calendar-check" disabled={busy || !date} onClick={() => patch({ scheduled_for: date }, t("calendar.scheduled_for", { date: fmtDay(date) }))}>{t("calendar.schedule")}</Button>
            </div>
            {published ? (
              <Button variant="secondary" leadingIcon="undo-2" disabled={busy} onClick={() => patch({ status: "ready" }, t("calendar.moved_back"))}>{t("calendar.back_to_ready")}</Button>
            ) : (
              <Button variant="primary" leadingIcon="badge-check" disabled={busy} onClick={() => patch({ status: "published" }, t("calendar.marked_published"))}>{t("calendar.mark_published")}</Button>
            )}
          </>
        )}
        {!isBrief && <div style={{ fontSize: 12, color: "var(--text-faint)", lineHeight: 1.5 }}>{t("calendar.suggestion_note")}</div>}
      </div>
    </Modal>
  );
}

function ContentPlan({ onNavigate }) {
  const { loading, data, reload } = useApi("/api/calendar");
  const [modal, setModal] = React.useState(null); // a plan entry
  const [drawer, setDrawer] = React.useState(null); // { briefId } | { keyword }
  const [savingCadence, setSavingCadence] = React.useState(false);
  const [savedRow, setSavedRow] = React.useState(null); // loaded brief row for the saved drawer
  const plan = data && data.plan;
  const today = todayIso();

  const setCadence = async (id) => {
    setSavingCadence(true);
    const r = await api.patch("/api/onboarding/wizard", { cadence: id });
    setSavingCadence(false);
    if (r.ok) { toast(t("calendar.cadence_set", { cadence: cadenceLabel(id).toLowerCase() }), { tone: "success" }); reload(); }
    else toast(r.error || t("calendar.cadence_failed"), { tone: "error" });
  };

  // Open the right drawer for an entry: saved brief -> read drawer (fetch the
  // row), suggestion -> generate drawer by phrase.
  const openBrief = async (entry) => {
    if (entry.briefId) {
      const r = await api.get("/api/briefs/" + entry.briefId);
      if (r.ok) setSavedRow(r.data.brief);
      else toast(r.error || t("calendar.load_failed"), { tone: "error" });
    } else {
      setDrawer({ keyword: entry.keyword });
    }
  };

  const byDate = {};
  if (plan) for (const e of plan.entries) (byDate[e.date] = byDate[e.date] || []).push(e);
  const weeks = plan ? weekRows(plan.start, plan.days) : [];
  const empty = plan && plan.entries.length === 0;
  const phone = window.LTQ.usePhone ? window.LTQ.usePhone() : false;
  // Phone agenda: the 7-column month is unreadable at 390px — list the days
  // that actually have entries (plus today), in order.
  const agendaDays = [];
  if (phone && plan) {
    for (const row of weeks) for (const day of row) {
      const entries = byDate[day.iso] || [];
      if (day.inWindow && (entries.length || day.iso === today)) agendaDays.push({ ...day, entries });
    }
  }

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      <SectionTitle eyebrow={t("calendar.eyebrow")} title={t("nav.calendar")}
        sub={t("calendar.sub")} />
      <PlanStrip plan={plan} loading={loading} onCadence={setCadence} savingCadence={savingCadence} />

      {loading && !plan ? (
        <Card pad={24}><span className="lt-shimmer" style={{ display: "block", height: 320, borderRadius: 10, background: "var(--ink-100)" }} /></Card>
      ) : empty ? (
        <Card pad={0}><EmptyState icon="calendar-days" sq="idle" title={t("calendar.empty_title")}
          body={t("calendar.empty_body")}
          action={<Button variant="primary" leadingIcon="search" onClick={() => onNavigate && onNavigate("research")}>{t("calendar.find_keywords")}</Button>} /></Card>
      ) : plan && phone ? (
        <Card pad={0} data-tour="calendar-grid">
          {agendaDays.map((day, i) => {
            const isToday = day.iso === today;
            return (
              <div key={day.iso} style={{ display: "flex", gap: 12, padding: "13px 14px", borderBottom: i < agendaDays.length - 1 ? "1px solid var(--border-subtle)" : "none" }}>
                <div style={{ flex: "none", width: 44, textAlign: "center" }}>
                  <div className="lt-num" style={{ fontFamily: "var(--font-mono)", fontSize: 16, fontWeight: 700, lineHeight: 1.2,
                    color: isToday ? "#fff" : "var(--text-strong)", background: isToday ? "var(--accent-500)" : "var(--ink-50)",
                    borderRadius: 10, padding: "6px 0 2px" }}>
                    {Number(day.iso.slice(8))}
                    <div style={{ fontSize: 9.5, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.05em", paddingBottom: 4,
                      color: isToday ? "rgba(255,255,255,0.85)" : "var(--text-faint)" }}>
                      {window.LTQ.fmtDate ? window.LTQ.fmtDate(new Date(day.iso + "T00:00:00Z"), { weekday: "short", timeZone: "UTC" }) : ""}
                    </div>
                  </div>
                </div>
                <div style={{ flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 6, justifyContent: "center" }}>
                  {day.entries.length === 0
                    ? <span style={{ fontSize: 12.5, color: "var(--text-faint)" }}>{t("calendar.today")}</span>
                    : day.entries.map((e, j) => <EntryChip key={j} entry={e} onOpen={setModal} />)}
                </div>
              </div>
            );
          })}
        </Card>
      ) : plan ? (
        <Card pad={0} data-tour="calendar-grid" style={{ overflow: "visible" }}>
          <div className="lt-keep-grid" style={{ display: "grid", gridTemplateColumns: "repeat(7, minmax(0,1fr))", borderBottom: "1px solid var(--border-subtle)" }}>
            {[1, 2, 3, 4, 5, 6, 7].map((n) => (window.LTQ.fmtDate ? window.LTQ.fmtDate(new Date(Date.UTC(2024, 0, n)), { weekday: "short", timeZone: "UTC" }) : ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"][n-1])).map((d) => (
              <div key={d} style={{ padding: "9px 10px", fontSize: 10.5, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--text-faint)" }}>{d}</div>
            ))}
          </div>
          {weeks.map((row, wi) => (
            <div key={wi} className="fx-enter lt-keep-grid" style={{ "--enter-delay": wi * 60 + "ms", display: "grid", gridTemplateColumns: "repeat(7, minmax(0,1fr))", borderBottom: wi < weeks.length - 1 ? "1px solid var(--border-subtle)" : "none" }}>
              {row.map((day, di) => {
                const isToday = day.iso === today;
                const entries = byDate[day.iso] || [];
                return (
                  <div key={day.iso} style={{ minHeight: 92, padding: "8px 8px 10px", borderRight: di < 6 ? "1px solid var(--border-subtle)" : "none",
                    background: day.inWindow ? "var(--paper)" : "var(--ink-50)", opacity: day.inWindow ? 1 : 0.55 }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 6 }}>
                      <span className="lt-num" style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, fontWeight: isToday ? 700 : 600,
                        color: isToday ? "#fff" : day.inWindow ? "var(--text-body)" : "var(--text-faint)",
                        background: isToday ? "var(--accent-500)" : "transparent", borderRadius: 999,
                        minWidth: 20, height: 20, display: "inline-grid", placeItems: "center", padding: "0 5px" }}>{Number(day.iso.slice(8))}</span>
                      {isToday && <span style={{ fontSize: 10, fontWeight: 700, color: "var(--accent-500)", letterSpacing: "0.04em" }}>{t("calendar.today")}</span>}
                    </div>
                    <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                      {entries.map((e, i) => <EntryChip key={i} entry={e} onOpen={setModal} />)}
                    </div>
                  </div>
                );
              })}
            </div>
          ))}
        </Card>
      ) : null}

      {modal && <EntryModal entry={modal} onClose={() => setModal(null)} onOpenBrief={openBrief} onChanged={reload} />}
      {drawer && <BriefDrawer keyword={drawer.keyword} onClose={() => setDrawer(null)} onSaved={reload} />}
      {savedRow && <SavedBriefDrawer row={savedRow} onClose={() => setSavedRow(null)} onDeleted={reload} />}
    </div>
  );
}
window.LTQ.ContentPlan = ContentPlan;
})();
