// ————————————————————————————————————————————————————————————————
// Reports list view — recently generated DD reports
// ————————————————————————————————————————————————————————————————

const { useState: LUS, useMemo: LUM } = React;

function ReportsList({ lang, onOpen, onOpenReport }) {
  const [q, setQ] = LUS("");
  const [sortBy, setSortBy] = LUS("date");
  const items = LUM(() => {
    const list = [];
    for (const th of window.THEMES) {
      const rep = window.themeReport(th.id);
      if (!rep) continue;
      // Aggregate per-theme stats
      const tickers = th.tickers.filter((t) => window.STOCKS[t]);
      const chgs = tickers.map((t) => window.STOCKS[t].chg);
      const avg = chgs.length
        ? chgs.reduce((a, b) => a + b, 0) / chgs.length
        : 0;
      const mcap = tickers.reduce(
        (a, t) => a + (window.STOCKS[t]?.mcap || 0),
        0,
      );
      // Count sources cited
      let nSources = 0;
      const seen = new Set();
      for (const tk of th.tickers) {
        const ev = window.stockEvidence(tk);
        if (!ev) continue;
        for (const e of ev.evidence || [])
          for (const r of e.refs || []) {
            if (!seen.has(r)) {
              seen.add(r);
              nSources++;
            }
          }
      }
      list.push({
        id: th.id,
        theme: th,
        report: rep,
        date: rep.date,
        count: tickers.length,
        mcap,
        avg,
        nSources,
        errata: (rep.errata || []).length || 0,
      });
    }
    const s = (q || "").toLowerCase();
    let f = list.filter(
      (r) =>
        !s ||
        (r.report.title || "").toLowerCase().includes(s) ||
        (r.theme.name || "").toLowerCase().includes(s) ||
        (r.theme?.jp || "").includes(q),
    );
    if (sortBy === "date")
      f.sort((a, b) => (b.date || "").localeCompare(a.date || ""));
    if (sortBy === "size") f.sort((a, b) => b.count - a.count);
    if (sortBy === "mcap") f.sort((a, b) => b.mcap - a.mcap);
    return f;
  }, [q, sortBy, window._reportsReady]);  // recompute when the deferred report blob lands

  return (
    <div className="reports-view">
      <header className="reports-hero">
        <div className="reports-hero-l">
          <div className="theme-hero-label">
            <span
              className="tc-dot"
              style={{
                background: "var(--accent)",
                boxShadow: "0 0 10px var(--accent)",
              }}
            />
            {lang === "jp" ? "レポートライブラリ" : "Reports library"}
          </div>
          <h1 className="theme-hero-n">
            {lang === "jp" ? "最近作成された調査" : "Recent research"}
          </h1>
          <div className="theme-hero-sub">
            {(window.ALL_REPORTS || []).length}{" "}
            {lang === "jp" ? "レポート" : "published reports"}
            <span className="dot">·</span>
            {window.THEMES.length}{" "}
            {lang === "jp" ? "テーマ追跡中" : "themes tracked"}
            <span className="dot">·</span>
            {Object.keys(window.SOURCES || {}).length}{" "}
            {lang === "jp" ? "参照ソース" : "reference sources"}
          </div>
        </div>
        <div className="reports-hero-r">
          <input
            className="reports-search"
            placeholder={lang === "jp" ? "レポートを検索…" : "Search reports…"}
            value={q}
            onChange={(e) => setQ(e.target.value)}
          />
          <div className="seg small">
            <button
              className={sortBy === "date" ? "on" : ""}
              onClick={() => setSortBy("date")}
            >
              {lang === "jp" ? "日付" : "Date"}
            </button>
            <button
              className={sortBy === "size" ? "on" : ""}
              onClick={() => setSortBy("size")}
            >
              {lang === "jp" ? "銘柄数" : "Size"}
            </button>
            <button
              className={sortBy === "mcap" ? "on" : ""}
              onClick={() => setSortBy("mcap")}
            >
              {lang === "jp" ? "時価総額" : "Mcap"}
            </button>
          </div>
        </div>
      </header>

      <div className="reports-list">
        <div
          className="reports-list-h"
          style={{ gridTemplateColumns: "100px 1fr 120px 80px" }}
        >
          <div>{lang === "jp" ? "日付" : "Date"}</div>
          <div>{lang === "jp" ? "レポート" : "Report"}</div>
          <div>{lang === "jp" ? "テーマ" : "Theme"}</div>
          <div></div>
        </div>
        {(window.ALL_REPORTS || [])
          .filter((r) => {
            // Hide rounds subsumed into a topic's revision history — the canonical
            // dossier (isTopic) represents them; revisions live in its drawer.
            if (r.isRevision) return false;
            if (!q) return true;
            const s = q.toLowerCase();
            return (
              (r.title || "").toLowerCase().includes(s) ||
              (r.slug || "").includes(s) ||
              (r.theme || "").includes(s)
            );
          })
          .map((r, i) => (
            <button
              key={r.slug}
              className="report-row"
              onClick={() => onOpenReport && onOpenReport(r.slug)}
              style={{
                animationDelay: i * 30 + "ms",
                gridTemplateColumns: "100px 1fr 120px 80px",
              }}
            >
              <div className="report-row-date">
                {r.date}
                {r.time && <small>{r.time}</small>}
              </div>
              <div className="report-row-main">
                <h3 className="report-row-t">{r.title}</h3>
                {r.sections && r.sections.length > 0 && (
                  <p className="report-row-s">
                    {r.sections.slice(0, 3).join(" · ")}
                  </p>
                )}
              </div>
              <div className="report-row-stat">
                <small>{r.theme}</small>
              </div>
              <div className="report-row-cta">Open →</div>
            </button>
          ))}
      </div>
    </div>
  );
}

window.ReportsList = ReportsList;

// ——————————————————————————————————————————————————————————————
// Markdown export & GPT-friendly text export of a theme report
// ——————————————————————————————————————————————————————————————
window.reportToMarkdown = function (themeId) {
  const theme = window.THEMES.find((t) => t.id === themeId);
  const rep = window.themeReport(themeId);
  if (!theme || !rep) return "";
  const lines = [];
  // sources order
  const ord = new Map();
  let n = 1;
  for (const tk of theme.tickers) {
    const ev = window.stockEvidence(tk);
    if (!ev) continue;
    for (const e of ev.evidence || [])
      for (const r of e.refs || []) if (!ord.has(r)) ord.set(r, n++);
  }
  lines.push(`# ${rep.title}`);
  lines.push("");
  lines.push(`*${rep.subtitle}*`);
  lines.push("");
  lines.push(
    `**${rep.date} · ${theme.tickers.length} stocks · ${ord.size} sources cited**`,
  );
  lines.push("");
  lines.push("---");
  lines.push("");
  lines.push("## Executive summary");
  lines.push("");
  lines.push(rep.summary);
  lines.push("");
  lines.push("## Portfolio overview");
  lines.push("");
  lines.push(
    "| # | Ticker | Company | Tier | PE | ROE | Op Mar | Rev g | Yield |",
  );
  lines.push(
    "|---|--------|---------|------|----|----|--------|-------|-------|",
  );
  let i = 1;
  for (const b of rep.convictionBuckets || []) {
    for (const tk of b.tickers || []) {
      const s = window.STOCKS[tk] || {};
      const m = window.stockMeta(tk);
      lines.push(
        `| ${i++} | ${tk} | ${s.name || ""} | ${b.tier} | ${m.pe > 0 ? m.pe.toFixed(1) : "N/M"} | ${m.roe?.toFixed(1)}% | ${m.opMargin?.toFixed(1)}% | ${m.revGrowth >= 0 ? "+" : ""}${m.revGrowth?.toFixed(1)}% | ${m.divYield?.toFixed(2)}% |`,
      );
    }
  }
  lines.push("");
  lines.push("## Conviction tiers");
  lines.push("");
  for (const b of rep.convictionBuckets || []) {
    lines.push(`### ${b.tier} conviction — ${(b.tickers || []).length} stocks`);
    lines.push("");
    lines.push(b.note);
    lines.push("");
    lines.push(
      (b.tickers || [])
        .map((t) => `- **${t}** ${window.STOCKS[t]?.name || ""}`)
        .join("\n"),
    );
    lines.push("");
  }
  lines.push("## Stock-by-stock");
  lines.push("");
  for (const tk of theme.tickers) {
    const s = window.STOCKS[tk];
    if (!s) continue;
    const m = window.stockMeta(tk);
    const ev = window.stockEvidence(tk);
    lines.push(`### ${tk} — ${s.name}`);
    lines.push("");
    lines.push(`*${m.positioning}*`);
    lines.push("");
    lines.push(`**Thesis.** ${m.thesis}`);
    lines.push("");
    if (ev?.evidence?.length) {
      lines.push(`**Evidence.**`);
      lines.push("");
      ev.evidence.forEach((e, idx) => {
        const refs = (e.refs || [])
          .map((r) => `[${ord.get(r) || "?"}]`)
          .join("");
        lines.push(`${idx + 1}. ${e.claim} ${refs}`.trim());
      });
      lines.push("");
    }
    lines.push(
      `**Snapshot.** PE ${m.pe > 0 ? m.pe.toFixed(1) : "N/M"} · ROE ${m.roe?.toFixed(1)}% · OpMar ${m.opMargin?.toFixed(1)}% · RevG ${m.revGrowth >= 0 ? "+" : ""}${m.revGrowth?.toFixed(1)}% · Yield ${m.divYield?.toFixed(2)}% · Mcap ¥${(s.mcap / 1000).toFixed(2)}T`,
    );
    lines.push("");
    if (ev?.filings?.length) {
      lines.push(
        `**Filings & references.** ${ev.filings.map((f) => `[${f.label}](${f.url})`).join(" · ")}`,
      );
      lines.push("");
    }
  }
  if (rep.errata || []?.length) {
    lines.push("## Data corrections (errata)");
    lines.push("");
    lines.push("| Ticker | Metric | Original | Actual | Source | Impact |");
    lines.push("|--------|--------|----------|--------|--------|--------|");
    for (const e of rep.errata || []) {
      lines.push(
        `| ${e.ticker} | ${e.metric} | ${e.original} | ${e.actual} | ${e.source} | ${e.impact} |`,
      );
    }
    lines.push("");
  }
  lines.push("## Methodology");
  lines.push("");
  lines.push(rep.methodology);
  lines.push("");
  lines.push("## Sources & references");
  lines.push("");
  for (const [id, num] of Array.from(ord.entries()).sort(
    (a, b) => a[1] - b[1],
  )) {
    const src = window.source(id);
    if (!src) continue;
    lines.push(
      `[${num}] **${src.publisher}** · ${src.date} — *${src.title}* — ${src.url}`,
    );
  }
  lines.push("");
  lines.push("---");
  lines.push("*Kairos·JP Research · AI-assisted, not investment advice.*");
  return lines.join("\n");
};

// Compact GPT-friendly text — strips formatting, optimized for paste-into-chat
window.reportToGptText = function (themeId) {
  const md = window.reportToMarkdown(themeId);
  return md; // markdown is already good for GPT
};

// Helpers exposed for buttons
window.copyReportToClipboard = async function (themeId) {
  const text = window.reportToGptText(themeId);
  try {
    await navigator.clipboard.writeText(text);
    return true;
  } catch (e) {
    // Fallback
    const ta = document.createElement("textarea");
    ta.value = text;
    document.body.appendChild(ta);
    ta.select();
    document.execCommand("copy");
    ta.remove();
    return true;
  }
};

window.downloadReportMd = function (themeId) {
  const md = window.reportToMarkdown(themeId);
  const rep = window.themeReport(themeId);
  const blob = new Blob([md], { type: "text/markdown;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `kairos-${themeId}-${rep?.date || "report"}.md`;
  document.body.appendChild(a);
  a.click();
  a.remove();
  setTimeout(() => URL.revokeObjectURL(url), 1000);
};
