// SQSEO app, Content Brief drawer + saved-briefs UI. A brief turns a discovered
// keyword into a publish-ready outline (titles, meta, cluster-driven H2s, FAQs,
// internal links, GEO note). Generated on demand via GET /api/brief/:id or
// POST /api/brief/preview; saved via POST /api/briefs; exported as Markdown.
(function init(){
if(!window.LongtailIQDesignSystem_ae8f12 || !window.LTQ || !window.LTQ.api){return setTimeout(init,30);}
const React = window.React;
const DS = window.LongtailIQDesignSystem_ae8f12;
const { Icon, OpportunityScore, Card } = DS;
const { api, toast, Score, Modal } = window.LTQ;
const t = (k, v) => (window.LTQ.t ? window.LTQ.t(k, v) : k);

// ---- helpers ----
function downloadText(filename, text, type){
  const blob = new Blob([text], { type: type || "text/plain;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a"); a.href = url; a.download = filename;
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(() => URL.revokeObjectURL(url), 1500);
}
const slug = (s) => ("brief-" + (s || "brief")).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "brief";
async function copyText(text){ try { await navigator.clipboard.writeText(text); } catch (e) {} toast(t("brief.copied_md"), { tone: "success" }); }

const GroundedBadge = () => (
  <span title={t("brief.grounded_title")} style={{ display: "inline-flex", alignItems: "center", gap: 4, fontSize: 10.5, fontWeight: 700, letterSpacing: "0.02em", textTransform: "uppercase", color: "var(--accent-600)", background: "var(--accent-50, #ecfdf5)", border: "1px solid var(--accent-100)", borderRadius: 999, padding: "2px 8px" }}>
    <Icon name="radar" size={11} /> Search Console
  </span>
);

const Eyebrow = ({ children }) => (
  <div style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--text-faint)", marginBottom: 8 }}>{children}</div>
);

// ---- the brief document body (shared by generate + saved views) ----
function BriefBody({ brief }){
  if (!brief) return null;
  const wc = brief.wordCount || { min: 0, max: 0 };
  const metrics = [
    [t("results.col_score"), brief.opportunity],
    [t("research.difficulty"), brief.difficulty],
    [t("brief.est_volume"), (brief.searchVolume || 0).toLocaleString()],
    [t("brief.words"), wc.min && wc.max ? wc.min.toLocaleString() + "–" + wc.max.toLocaleString() : "—"],
  ];
  const meta2 = [brief.intent, window.LTQ.dataLabel("funnel", brief.funnel), window.LTQ.dataLabel("type", brief.contentType), window.LTQ.dataLabel("serp", brief.serp)].filter(Boolean);
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
      <div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 8 }}>
          {brief.grounded && <GroundedBadge />}
          {meta2.length > 0 && <span style={{ fontSize: 12, color: "var(--text-faint)", fontWeight: 600 }}>{meta2.join(" · ")}</span>}
        </div>
        <h2 style={{ fontFamily: "var(--font-display)", fontSize: 22, fontWeight: 600, letterSpacing: "-0.02em", color: "var(--text-strong)", lineHeight: 1.25, textTransform: "capitalize" }}>{brief.keyword}</h2>
      </div>

      <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
        <Score score={brief.opportunity || 0} width={120} />
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, flex: 1 }}>
          {metrics.map(([l, v], i) => (
            <div key={i} style={{ border: "1px solid var(--border-subtle)", borderRadius: 10, padding: "8px 11px" }}>
              <div style={{ fontSize: 10.5, color: "var(--text-faint)", marginBottom: 2 }}>{l}</div>
              <div className="lt-num" style={{ fontFamily: "var(--font-mono)", fontSize: 14, fontWeight: 700, color: "var(--text-strong)" }}>{v}</div>
            </div>
          ))}
        </div>
      </div>

      {brief.angle && (
        <div style={{ display: "flex", alignItems: "flex-start", gap: 9, padding: "12px 14px", background: "var(--ink-50)", borderRadius: 10, fontSize: 13, color: "var(--text-body)", lineHeight: 1.5 }}>
          <Icon name="compass" size={15} style={{ color: "var(--accent-500)", marginTop: 1, flex: "none" }} />
          <span><b style={{ color: "var(--text-strong)" }}>{t("brief.angle")}</b> {brief.angle}</span>
        </div>
      )}

      <div>
        <Eyebrow>{t("brief.title_options")}</Eyebrow>
        <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
          {(brief.titles || []).map((title, i) => (
            <button key={i} onClick={() => copyText(title)} title={t("brief.click_to_copy")} style={{ display: "flex", alignItems: "center", gap: 9, textAlign: "left", padding: "9px 11px", borderRadius: 9, border: "1px solid var(--border-subtle)", background: "var(--surface-card)", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 13.5, fontWeight: 600, color: "var(--text-strong)" }}
              onMouseEnter={e => e.currentTarget.style.background = "var(--ink-50)"} onMouseLeave={e => e.currentTarget.style.background = "var(--surface-card)"}>
              <Icon name="type" size={14} style={{ color: "var(--text-faint)", flex: "none" }} />{title}
            </button>
          ))}
        </div>
      </div>

      {brief.metaDescription && (
        <div>
          <Eyebrow>{t("brief.meta_description")}</Eyebrow>
          <div style={{ padding: "11px 13px", borderRadius: 10, border: "1px dashed var(--border-strong)", background: "var(--ink-50)", fontSize: 13, color: "var(--text-body)", lineHeight: 1.5 }}>{brief.metaDescription}</div>
        </div>
      )}

      <div>
        <Eyebrow>{t("brief.outline")}</Eyebrow>
        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {(brief.outline || []).map((s, i) => (
            <div key={i} className="lt-fade-up" style={{ animationDelay: (i * 45) + "ms", border: "1px solid var(--border-subtle)", borderRadius: 11, padding: "12px 14px", background: "var(--surface-card)" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: s.points && s.points.length ? 8 : 0 }}>
                <span className="lt-num" style={{ fontFamily: "var(--font-mono)", fontSize: 11, fontWeight: 700, color: "var(--accent-600)", flex: "none" }}>H2·{String(i + 1).padStart(2, "0")}</span>
                <span style={{ fontSize: 14, fontWeight: 700, color: "var(--text-strong)", lineHeight: 1.3, textTransform: "capitalize" }}>{s.h2}</span>
              </div>
              {s.points && s.points.length > 0 && (
                <ul style={{ margin: 0, paddingLeft: 0, listStyle: "none", display: "flex", flexDirection: "column", gap: 5 }}>
                  {s.points.map((p, j) => (
                    <li key={j} style={{ display: "flex", alignItems: "flex-start", gap: 8, fontSize: 12.5, color: "var(--text-muted)", lineHeight: 1.5 }}>
                      <span style={{ width: 4, height: 4, borderRadius: 999, background: "var(--accent-400)", flex: "none", marginTop: 7 }} />{p}
                    </li>
                  ))}
                </ul>
              )}
            </div>
          ))}
        </div>
      </div>

      {brief.faqs && brief.faqs.length > 0 && (
        <div>
          <Eyebrow>{t("brief.faqs")}</Eyebrow>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {brief.faqs.map((f, i) => (
              <div key={i} style={{ display: "flex", alignItems: "flex-start", gap: 8, fontSize: 13, color: "var(--text-body)", lineHeight: 1.45 }}>
                <Icon name="help-circle" size={14} style={{ color: "var(--text-faint)", marginTop: 2, flex: "none" }} />{f}
              </div>
            ))}
          </div>
        </div>
      )}

      {brief.internalLinks && brief.internalLinks.length > 0 && (
        <div>
          <Eyebrow>{t("brief.internal_links")}</Eyebrow>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
            {brief.internalLinks.map((l, i) => (
              <span key={i} style={{ display: "inline-flex", alignItems: "center", gap: 6, height: 26, padding: "0 11px", borderRadius: 999, background: "var(--ink-50)", border: "1px solid var(--border-subtle)", fontSize: 12, fontWeight: 600, color: "var(--text-body)", textTransform: "capitalize" }}>
                <Icon name="link" size={12} style={{ color: "var(--accent-500)" }} />{l}
              </span>
            ))}
          </div>
        </div>
      )}

      {brief.geoNote && (
        <div style={{ display: "flex", alignItems: "flex-start", gap: 9, padding: "12px 14px", borderRadius: 10, border: "1px solid var(--accent-100)", background: "var(--accent-50, #ecfdf5)", fontSize: 12.5, color: "var(--text-body)", lineHeight: 1.5 }}>
          <Icon name="sparkles" size={15} style={{ color: "var(--accent-600)", marginTop: 1, flex: "none" }} />
          <span><b style={{ color: "var(--text-strong)" }}>{t("brief.geo_note")}</b> {brief.geoNote}</span>
        </div>
      )}
    </div>
  );
}

// ---- drawer chrome (slide-in panel) ----
function DrawerShell({ eyebrow, icon, onClose, children, footer }){
  React.useEffect(() => { const onKey = (e) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, []);
  const ReactDOM = window.ReactDOM;
  const overlay = (
    <div onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }} style={{ position: "fixed", inset: 0, zIndex: 130, background: "rgba(12,16,14,0.42)", display: "flex", justifyContent: "flex-end" }}>
      <div className="lt-drawer-in" style={{ width: "min(520px, 96vw)", height: "100%", background: "var(--paper)", borderLeft: "1px solid var(--border-subtle)", boxShadow: "var(--shadow-lg)", display: "flex", flexDirection: "column" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12, padding: "18px 24px 14px", borderBottom: "1px solid var(--border-subtle)" }}>
          <span className="lt-eyebrow" style={{ display: "inline-flex", alignItems: "center", gap: 7 }}><Icon name={icon || "file-pen-line"} size={14} /> {eyebrow}</span>
          <button onClick={onClose} aria-label={t("chrome.close")} style={{ width: 30, height: 30, display: "grid", placeItems: "center", border: "none", background: "transparent", cursor: "pointer", color: "var(--text-faint)" }}><Icon name="x" size={18} /></button>
        </div>
        <div className="lt-scroll" style={{ flex: 1, overflowY: "auto", padding: 24 }}>{children}</div>
        {footer && <div style={{ display: "flex", gap: 8, padding: "14px 20px", borderTop: "1px solid var(--border-subtle)", background: "var(--surface-card)" }}>{footer}</div>}
      </div>
    </div>
  );
  // Portal to body — the route wrapper's entrance transform otherwise hijacks
  // position:fixed and the drawer sizes against the page, not the viewport
  // (same rule as shared.jsx BottomSheet).
  return ReactDOM && ReactDOM.createPortal ? ReactDOM.createPortal(overlay, document.body) : overlay;
}

const SpinnerBlock = () => (
  <div className="lt-loading-delayed" style={{ padding: 60, textAlign: "center", color: "var(--text-faint)" }}>
    <span className="lt-spin" style={{ display: "inline-block", width: 22, height: 22, border: "2px solid var(--accent-200)", borderTopColor: "var(--accent-500)", borderRadius: 999 }} />
    <div style={{ marginTop: 12, fontSize: 13 }}>{t("brief.building")}</div>
  </div>
);

const btnDark = { height: 38, padding: "0 14px", borderRadius: 9, border: "none", background: "var(--ink-900)", color: "#fff", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 600, display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7 };
const btnLight = { height: 38, padding: "0 14px", borderRadius: 9, border: "1px solid var(--border-subtle)", background: "var(--paper)", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 600, color: "var(--text-body)", display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7 };

// ---- generate-mode drawer: keywordId (stored kw) OR keyword (free phrase) ----
function BriefDrawer({ keywordId, keyword, onClose, onSaved }){
  const [state, setState] = React.useState(null); // { brief, markdown, keywordId, savedId }
  const [savedId, setSavedId] = React.useState(null);
  const [saving, setSaving] = React.useState(false);
  React.useEffect(() => {
    let alive = true; setState(null);
    const p = keywordId ? api.get("/api/brief/" + keywordId) : api.post("/api/brief/preview", { keyword });
    p.then((r) => {
      if (!alive) return;
      if (r.ok) { setState(r.data); setSavedId(r.data.savedId || null); }
      else { toast(r.error || t("brief.generate_failed"), { tone: "error" }); onClose(); }
    });
    return () => { alive = false; };
  }, [keywordId, keyword]);

  const brief = state && state.brief;
  const save = async () => {
    if (!state) return;
    setSaving(true);
    const payload = state.keywordId ? { keywordId: state.keywordId } : { keyword: brief.keyword };
    const r = await api.post("/api/briefs", payload);
    setSaving(false);
    if (r.ok) { setSavedId(r.data.brief.id); toast(t("brief.saved"), { tone: "success" }); onSaved && onSaved(); if (window.LTQEngine) window.LTQEngine.celebrate("save"); if (window.LTQ.sqCheer) window.LTQ.sqCheer(); }
    else toast(r.error || t("brief.save_failed"), { tone: "error" });
  };
  const footer = brief ? (
    <>
      <button onClick={save} disabled={saving} style={{ ...btnDark, flex: 1 }}>
        {saving ? <span className="lt-spin" style={{ width: 14, height: 14, border: "2px solid rgba(255,255,255,0.4)", borderTopColor: "#fff", borderRadius: 999 }} /> : <Icon name={savedId ? "check" : "bookmark-plus"} size={15} />}
        {savedId ? t("brief.saved_label") : t("brief.save")}
      </button>
      <button onClick={() => copyText(state.markdown)} style={btnLight}><Icon name="clipboard" size={15} /> {t("brief.copy_md")}</button>
      <button onClick={() => downloadText(slug(brief.keyword) + ".md", state.markdown, "text/markdown;charset=utf-8")} style={btnLight} title={t("brief.download_md")}><Icon name="download" size={15} /></button>
    </>
  ) : null;
  return <DrawerShell eyebrow={t("research.content_brief")} onClose={onClose} footer={footer}>{brief ? <BriefBody brief={brief} /> : <SpinnerBlock />}</DrawerShell>;
}

// ---- saved-mode drawer: view a stored brief (row has .id + .brief) ----
function SavedBriefDrawer({ row, onClose, onDeleted }){
  const [busy, setBusy] = React.useState(false);
  // The trash sits one slip away from Copy/Download, so it confirms first —
  // the same pattern Saved Lists, projects and API keys use.
  const [confirmDel, setConfirmDel] = React.useState(false);
  const brief = row.brief;
  const exportUrl = "/api/briefs/" + row.id + "/export.md";
  const copyMd = async () => {
    try { const res = await fetch(exportUrl, { credentials: "same-origin" }); await copyText(await res.text()); }
    catch (e) { toast(t("brief.copy_failed"), { tone: "error" }); }
  };
  const del = async () => {
    setConfirmDel(false);
    setBusy(true);
    const r = await api.del("/api/briefs/" + row.id);
    setBusy(false);
    if (r.ok) { toast(t("brief.deleted"), { tone: "success" }); onDeleted && onDeleted(); onClose(); }
    else toast(r.error || t("brief.delete_failed"), { tone: "error" });
  };
  const footer = (
    <>
      <a href={exportUrl} style={{ ...btnDark, flex: 1, textDecoration: "none" }}><Icon name="download" size={15} /> {t("brief.download_md")}</a>
      <button onClick={copyMd} style={btnLight}><Icon name="clipboard" size={15} /> {t("brief.copy_md")}</button>
      <button onClick={() => setConfirmDel(true)} disabled={busy} style={{ ...btnLight, color: "var(--viz-red)" }} title={t("brief.delete")} aria-label={t("brief.delete")}><Icon name="trash-2" size={15} /></button>
    </>
  );
  return (
    <DrawerShell eyebrow={t("brief.saved_brief")} onClose={onClose} footer={footer}>
      <BriefBody brief={brief} />
      {confirmDel && (
        <Modal title={t("settings.delete_q", { name: row.keyword || "" })} sub={t("brief.delete_sub")} onClose={() => setConfirmDel(false)} width={440}>
          <div style={{ display: "flex", justifyContent: "flex-end", gap: 8 }}>
            <button onClick={() => setConfirmDel(false)} style={{ height: 38, padding: "0 14px", borderRadius: 9, border: "1px solid var(--border-subtle)", background: "var(--paper)", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 600, color: "var(--text-body)" }}>{t("chrome.cancel")}</button>
            <button onClick={del} style={{ height: 38, padding: "0 16px", borderRadius: 9, border: "none", background: "var(--viz-red)", color: "#fff", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 600, display: "inline-flex", alignItems: "center", gap: 7 }}>
              <Icon name="trash-2" size={15} /> {t("brief.delete")}
            </button>
          </div>
        </Modal>
      )}
    </DrawerShell>
  );
}

Object.assign(window.LTQ, { BriefDrawer, SavedBriefDrawer, BriefBody, DrawerShell });
})();
