/* WAREHOUSE 2.0 · FEATURE 23 · owner-only cross-company AI optimization analysis */
(() => {
const W2 = window.W2;
const { t } = window.W2_LANG;
window.W2_LANG.addEN({
  "進化分析": "Evolution",
  "跨公司 AI 總領分析": "Cross-company AI optimization",
  "獨立研究 AI · 聚合分析秘書對話成效 · 持續保存問題、候選方案與快照": "Independent research AI · aggregate Secretary outcomes · persist findings, candidates and snapshots",
  "實驗性功能": "Experimental",
  "僅平台擁有者": "Platform owner only",
  "聚合資料邊界": "Aggregate data boundary",
  "此頁不接收或顯示原始對話、工具參數或原始模型回應；只接收經結構、敏感資料遮罩與群組門檻驗證的聚合拓撲、統計與優化方案。": "This page never receives or displays raw conversations, tool arguments, or raw model responses; it receives only aggregate topology, statistics, and proposals validated by schema, sensitive-data masking, and cohort thresholds.",
  "資料邊界驗證失敗，已停止呈現分析。": "The data-boundary check failed, so analysis rendering was stopped.",
  "分析視窗": "Analysis window",
  "近 {n} 天": "Last {n} days",
  "刷新快照": "Refresh snapshot",
  "立即分析": "Analyze now",
  "分析中…": "Analyzing…",
  "正在整理跨公司聚合資料…": "Preparing cross-company aggregate data…",
  "分析已完成並保存最新快照。": "Analysis completed and the latest snapshot was saved.",
  "分析載入失敗": "Analysis unavailable",
  "沒有把載入失敗顯示成零值；請重試或檢查平台優化器服務。": "A load failure is not shown as zero. Retry or inspect the platform optimizer service.",
  "重試": "Retry",
  "可分析公司": "Available companies",
  "公司覆蓋": "company coverage",
  "秘書對話": "Secretary conversations",
  "聚合計數": "aggregate count",
  "AI 運行": "AI runs",
  "完成率 {n}": "completion {n}",
  "總 Token": "Total tokens",
  "視窗用量": "window usage",
  "效果訊號": "Outcome signals",
  "只使用聚合結果與正式運行狀態，不以模型自評取代真實結果。": "Uses aggregate outcomes and authoritative run state; model self-evaluation never replaces real results.",
  "運行完成率": "Run completion",
  "運行失敗率": "Run failures",
  "確認完成率": "Confirmation completion",
  "回饋率": "Feedback rate",
  "平均耗時": "Average duration",
  "聚合訊息": "Aggregate messages",
  "確認事件": "Confirmation events",
  "回饋事件": "Feedback events",
  "問題發現": "Findings",
  "由跨公司訊號歸納的可驗證問題；不展示任何單一對話。": "Verifiable issues inferred from cross-company signals; no individual conversation is shown.",
  "目前沒有問題發現": "No findings yet",
  "完成一次分析後，問題模式會以版本化證據持續累積。": "After an analysis, versioned evidence will accumulate into problem patterns.",
  "證據 {n}": "{n} evidence points",
  "涉及 {n} 家公司": "Across {n} companies",
  "建議": "Recommendation",
  "候選方案": "Candidates",
  "每個方案都有狀態、風險與 revision；此頁不直接修改生產秘書。": "Every proposal carries status, risk and revision; this page never edits the production Secretary directly.",
  "目前沒有候選方案": "No candidates yet",
  "分析器提出的方案會保存在這裡，等待離線評估與治理。": "Optimizer proposals will be retained here for offline evaluation and governance.",
  "假設": "Hypothesis",
  "預期影響": "Expected impact",
  "風險": "Risk",
  "版本": "Revision",
  "建立於": "Created",
  "公司快照帳本": "Company snapshot ledger",
  "每家公司只保存本視窗的聚合計數與可用狀態。": "Stores only per-company aggregate counts and availability for this window.",
  "分析歷史": "Analysis history",
  "每次分析都保留聚合規模、發現與候選數量，供平台擁有者追蹤持續迭代。": "Each analysis retains aggregate scope and finding/candidate counts so platform owners can trace continuous iteration.",
  "尚無分析歷史": "No analysis history",
  "分析編號": "Analysis ID",
  "視窗": "Window",
  "覆蓋公司": "Companies",
  "發現": "Findings",
  "候選": "Candidates",
  "目標版本": "Objective",
  "分析引擎": "Engine",
  "建立者": "Created by",
  "公司": "Company",
  "狀態": "Status",
  "對話": "Conversations",
  "訊息": "Messages",
  "運行": "Runs",
  "完成": "Completed",
  "失敗": "Failed",
  "回饋": "Feedback",
  "確認": "Confirmations",
  "可用": "Available",
  "不可用": "Unavailable",
  "尚無公司快照": "No company snapshots",
  "資料生成於 {time}": "Generated {time}",
  "此功能只屬於有效的 Bonfire L11 平台擁有者。": "This feature is reserved for effective Bonfire L11 platform owners.",
  "當前登入沒有 is_platform_owner 權威標記，因此不會探測任何優化器端點。": "The current session has no authoritative is_platform_owner flag, so no optimizer endpoint will be probed.",
  "回總覽": "Back to overview",
});

const { useEffect, useMemo, useState } = React;
const { Band, Btn: B, Empty: EM, Folio, Icon: I, Kpi, Label: LB, Tag: T } = W2;
const WINDOW_OPTIONS = [7, 30, 90];
const objectOf = value => value && typeof value === "object" && !Array.isArray(value) ? value : {};
const arrayOf = value => Array.isArray(value) ? value : [];
const finite = value => Number.isFinite(Number(value)) ? Number(value) : null;
const count = value => {
  const parsed = finite(value);
  return parsed === null ? null : Math.max(0, Math.trunc(parsed));
};
const safeText = (value, limit = 700) => typeof value === "string"
  ? value.trim().slice(0, limit)
  : "";
const displayNumber = value => {
  const parsed = count(value);
  return parsed === null ? "—" : parsed.toLocaleString();
};
const percent = value => {
  const parsed = finite(value);
  if (parsed === null) return "—";
  const scaled = Math.abs(parsed) <= 1 ? parsed * 100 : parsed;
  return Math.max(0, scaled).toFixed(1).replace(/\.0$/, "") + "%";
};
const duration = value => {
  const parsed = finite(value);
  if (parsed === null) return "—";
  if (parsed < 1000) return Math.round(parsed) + " ms";
  return (parsed / 1000).toFixed(parsed < 10000 ? 1 : 0) + " s";
};
const timestamp = value => {
  if (!value) return "—";
  const parsed = new Date(value);
  return Number.isNaN(parsed.getTime()) ? safeText(String(value), 40) : parsed.toLocaleString();
};

const normalizeOverview = payload => {
  const outer = objectOf(payload);
  const source = Object.keys(objectOf(outer.analysis)).length ? objectOf(outer.analysis) : outer;
  const feature = objectOf(source.feature);
  const privacy = objectOf(source.privacy);
  if (
    feature.owner_only !== true ||
    privacy.aggregate_only !== true ||
    privacy.raw_transcripts_exposed !== false
  ) {
    throw new Error(t("資料邊界驗證失敗，已停止呈現分析。"));
  }
  const summary = objectOf(source.summary);
  const metrics = objectOf(source.metrics);
  return {
    feature: {
      id: count(feature.id),
      key: safeText(feature.key, 80),
      experimental: feature.experimental === true,
      owner_only: true,
    },
    summary: {
      window_days: count(summary.window_days),
      generated_at: safeText(summary.generated_at, 80),
      tenant_count: count(summary.tenant_count),
      available_tenant_count: count(summary.available_tenant_count),
      conversation_count: count(summary.conversation_count),
      message_count: count(summary.message_count),
      run_count: count(summary.run_count),
      completed_run_count: count(summary.completed_run_count),
      failed_run_count: count(summary.failed_run_count),
      feedback_count: count(summary.feedback_count),
      confirmation_count: count(summary.confirmation_count),
      total_tokens: count(summary.total_tokens),
      avg_duration_ms: finite(summary.avg_duration_ms),
    },
    metrics: {
      completion_rate: finite(metrics.completion_rate),
      failure_rate: finite(metrics.failure_rate),
      confirmation_completion_rate: finite(metrics.confirmation_completion_rate),
      feedback_rate: finite(metrics.feedback_rate),
    },
    findings: arrayOf(source.findings).map((raw, index) => {
      const item = objectOf(raw);
      return {
        key: safeText(item.key, 120) || "finding-" + index,
        severity: safeText(item.severity, 24).toLowerCase() || "info",
        category: safeText(item.category, 80),
        title: safeText(item.title, 240),
        description: safeText(item.description),
        evidence_count: count(item.evidence_count),
        tenant_count: count(item.tenant_count),
        recommendation: safeText(item.recommendation),
      };
    }),
    candidates: arrayOf(source.candidates).map((raw, index) => {
      const item = objectOf(raw);
      return {
        id: safeText(String(item.id == null ? "" : item.id), 120) || "candidate-" + index,
        status: safeText(item.status, 40).toLowerCase() || "draft",
        title: safeText(item.title, 240),
        hypothesis: safeText(item.hypothesis),
        expected_impact: safeText(item.expected_impact, 500),
        risk_level: safeText(item.risk_level, 40).toLowerCase() || "unknown",
        revision: count(item.revision),
        created_at: safeText(item.created_at, 80),
      };
    }),
    snapshots: arrayOf(source.snapshots).map((raw, index) => {
      const item = objectOf(raw);
      return {
        key: safeText(item.tenant_slug, 100) || "tenant-" + index,
        tenant_slug: safeText(item.tenant_slug, 100),
        tenant_name: safeText(item.tenant_name, 160),
        available: item.available === true,
        conversation_count: count(item.conversation_count),
        message_count: count(item.message_count),
        run_count: count(item.run_count),
        completed_run_count: count(item.completed_run_count),
        failed_run_count: count(item.failed_run_count),
        feedback_count: count(item.feedback_count),
        confirmation_count: count(item.confirmation_count),
        total_tokens: count(item.total_tokens),
        avg_duration_ms: finite(item.avg_duration_ms),
      };
    }),
    analysis_history: arrayOf(source.analysis_history).map((raw, index) => {
      const item = objectOf(raw);
      return {
        key: safeText(String(item.id == null ? "" : item.id), 120) || "analysis-" + index,
        id: safeText(String(item.id == null ? "" : item.id), 120),
        window_days: count(item.window_days),
        tenant_count: count(item.tenant_count),
        available_tenant_count: count(item.available_tenant_count),
        finding_count: count(item.finding_count),
        candidate_count: count(item.candidate_count),
        created_by_username: safeText(item.created_by_username, 120),
        created_at: safeText(item.created_at, 80),
        objective_version: safeText(String(item.objective_version == null ? "" : item.objective_version), 120),
        analysis_engine: safeText(item.analysis_engine, 160),
      };
    }),
    privacy: { aggregate_only: true, raw_transcripts_exposed: false },
  };
};

const severityRank = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
const severityTone = severity => severity === "critical" || severity === "high"
  ? "bad"
  : severity === "medium" ? "warn" : severity === "low" ? "plain" : "ok";
const statusTone = status => status === "validated" || status === "active"
  ? "ok"
  : status === "rejected" || status === "failed" ? "bad"
    : status === "testing" || status === "queued" ? "warn" : "plain";
const riskTone = risk => risk === "critical" || risk === "high"
  ? "bad"
  : risk === "medium" ? "warn" : "plain";

const AdminMark = () => (
  <div className="row g8 wrap" style={{ paddingTop: 14 }}>
    <span className="label" style={{ color: "var(--red)" }}>ADMIN · FEATURE 23</span>
    <T tone="redinv">{t("實驗性功能")}</T>
    <T tone="plain">{t("僅平台擁有者")}</T>
  </div>
);

const Denied = () => (
  <>
    <AdminMark/>
    <Folio no="22" en="AI OPTIMIZER" title={t("跨公司 AI 總領分析")}
      sub={t("此功能只屬於有效的 Bonfire L11 平台擁有者。")}/>
    <div className="rise" style={{ borderTop: "2px solid var(--red)", padding: "42px 0 64px" }}>
      <div className="mono" style={{ color: "var(--red)", fontSize: 34, fontWeight: 800 }}>ACCESS DENIED</div>
      <p style={{ maxWidth: 680, marginTop: 16, fontSize: 13.5, lineHeight: 1.8 }}>
        {t("當前登入沒有 is_platform_owner 權威標記，因此不會探測任何優化器端點。")}
      </p>
      <B icon="arrow" style={{ marginTop: 18 }} onClick={() => { location.hash = "#/dashboard"; }}>{t("回總覽")}</B>
    </div>
  </>
);

const Metric = ({ label, value, note }) => (
  <div className="panel" style={{ padding: 16, minHeight: 112 }}>
    <LB dim>{t(label)}</LB>
    <div className="mono" style={{ fontSize: 29, fontWeight: 760, marginTop: 13 }}>{value}</div>
    {note && <div className="muted" style={{ fontSize: 10.5, marginTop: 8 }}>{note}</div>}
  </div>
);

const OptimizerMain = () => {
  const [windowDays, setWindowDays] = useState(30);
  const [snapshot, setSnapshot] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [reloadNo, setReloadNo] = useState(0);

  useEffect(() => {
    const controller = new AbortController();
    setLoading(true); setError(""); setSnapshot(null);
    W2.json(
      "/api/platform/optimizer/overview?window_days=" + encodeURIComponent(windowDays),
      { signal: controller.signal }
    )
      .then(data => { if (!controller.signal.aborted) setSnapshot(normalizeOverview(data)); })
      .catch(reason => {
        if (!controller.signal.aborted && (!reason || reason.name !== "AbortError")) {
          setError((reason && reason.message) || String(reason));
        }
      })
      .finally(() => { if (!controller.signal.aborted) setLoading(false); });
    return () => controller.abort();
  }, [windowDays, reloadNo]);

  const summary = snapshot ? snapshot.summary : {};
  const metrics = snapshot ? snapshot.metrics : {};
  const findings = useMemo(() => snapshot
    ? snapshot.findings.slice().sort((a, b) =>
        (severityRank[a.severity] ?? 9) - (severityRank[b.severity] ?? 9) ||
        (b.evidence_count || 0) - (a.evidence_count || 0))
    : [], [snapshot]);
  const candidates = snapshot ? snapshot.candidates : [];
  const snapshots = snapshot ? snapshot.snapshots : [];
  const analysisHistory = snapshot ? snapshot.analysis_history : [];
  const coverage = summary.tenant_count
    ? Math.round(((summary.available_tenant_count || 0) / summary.tenant_count) * 100) + "%"
    : "—";

  return (
    <>
      <AdminMark/>
      <Folio no="22" en="AI OPTIMIZER" title={t("跨公司 AI 總領分析")}
        sub={t("獨立研究 AI · 聚合分析秘書對話成效 · 持續保存問題、候選方案與快照")}
        right={<div className="row g8 wrap">
          <label className="row g6" style={{ fontSize: 11.5, fontWeight: 700 }}>
            <span>{t("分析視窗")}</span>
            <select className="field" value={windowDays} disabled={loading}
              onChange={event => setWindowDays(Number(event.target.value))}
              style={{ width: 116, height: 34, fontSize: 11.5 }}>
              {WINDOW_OPTIONS.map(days => <option value={days} key={days}>{t("近 {n} 天", { n: days })}</option>)}
            </select>
          </label>
          <B icon="refresh" disabled={loading} onClick={() => setReloadNo(value => value + 1)}>{t("刷新快照")}</B>
        </div>}/>
      {error && <div role="alert" className="panel" style={{ marginTop: 14, padding: 18, borderColor: "var(--red)" }}>
        <LB red>{t("分析載入失敗")}</LB>
        <div style={{ marginTop: 10, fontSize: 13, fontWeight: 700, color: "var(--red)", overflowWrap: "anywhere" }}>{error}</div>
        <div className="muted" style={{ marginTop: 8, fontSize: 11.5 }}>{t("沒有把載入失敗顯示成零值；請重試或檢查平台優化器服務。")}</div>
        <B size="sm" icon="refresh" style={{ marginTop: 13 }} onClick={() => setReloadNo(value => value + 1)}>{t("重試")}</B>
      </div>}
      {loading && <div className="step-line" style={{ marginTop: 22 }}><I name="refresh" size={11}/>{t("正在整理跨公司聚合資料…")}</div>}

      {snapshot && <>
        <div className="panel row g12 wrap" style={{ marginTop: 14, padding: 14, borderColor: "var(--ok)" }}>
          <I name="shield" size={18} color="var(--ok)"/>
          <div style={{ flex: 1, minWidth: 240 }}>
            <LB>{t("聚合資料邊界")}</LB>
            <div className="muted" style={{ marginTop: 5, fontSize: 11.5, lineHeight: 1.6 }}>
              {t("此頁不接收或顯示原始對話、工具參數或原始模型回應；只接收經結構、敏感資料遮罩與群組門檻驗證的聚合拓撲、統計與優化方案。")}
            </div>
          </div>
          <T tone="ok" dot>AGGREGATE ONLY</T>
          <T tone="plain">NO RAW TRANSCRIPTS</T>
        </div>

        <div className="kpi-band">
          <Kpi label={t("可分析公司")} value={displayNumber(summary.available_tenant_count)}
            unit={"/ " + displayNumber(summary.tenant_count)} foot={<T tone="plain">{coverage} {t("公司覆蓋")}</T>}/>
          <Kpi label={t("秘書對話")} value={displayNumber(summary.conversation_count)}
            foot={<span className="muted">{t("聚合計數")}</span>}/>
          <Kpi label={t("AI 運行")} value={displayNumber(summary.run_count)}
            foot={<T tone="ok" dot>{t("完成率 {n}", { n: percent(metrics.completion_rate) })}</T>}/>
          <Kpi label={t("總 Token")} value={displayNumber(summary.total_tokens)}
            foot={<span className="muted">{t("視窗用量")}</span>}/>
        </div>

        <Band no="A" title={t("效果訊號")}
          sub={t("只使用聚合結果與正式運行狀態，不以模型自評取代真實結果。")}
          right={<span className="mono muted" style={{ fontSize: 10 }}>
            {t("資料生成於 {time}", { time: timestamp(summary.generated_at) })}
          </span>}>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(170px,1fr))", gap: 10 }}>
            <Metric label="運行完成率" value={percent(metrics.completion_rate)}
              note={displayNumber(summary.completed_run_count) + " / " + displayNumber(summary.run_count)}/>
            <Metric label="運行失敗率" value={percent(metrics.failure_rate)}
              note={displayNumber(summary.failed_run_count) + " failed"}/>
            <Metric label="確認完成率" value={percent(metrics.confirmation_completion_rate)}
              note={displayNumber(summary.confirmation_count) + " events"}/>
            <Metric label="回饋率" value={percent(metrics.feedback_rate)}
              note={displayNumber(summary.feedback_count) + " events"}/>
            <Metric label="平均耗時" value={duration(summary.avg_duration_ms)}/>
            <Metric label="聚合訊息" value={displayNumber(summary.message_count)}/>
          </div>
        </Band>

        <Band no="B" title={t("問題發現")}
          sub={t("由跨公司訊號歸納的可驗證問題；不展示任何單一對話。")}>
          {!findings.length
            ? <EM icon="check" title={t("目前沒有問題發現")}
                sub={t("完成一次分析後，問題模式會以版本化證據持續累積。")}/>
            : <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12 }}>
                {findings.map(item => <article className="panel" key={item.key}
                  style={{ padding: 16, borderTop: item.severity === "critical" || item.severity === "high" ? "3px solid var(--red)" : "1px solid var(--rule)" }}>
                  <div className="row spread g8 wrap">
                    <T tone={severityTone(item.severity)}>{item.severity.toUpperCase()}</T>
                    {item.category && <span className="label dim">{item.category}</span>}
                  </div>
                  <h3 style={{ marginTop: 13, fontSize: 17, lineHeight: 1.35 }}>{item.title || item.key}</h3>
                  {item.description && <p className="muted" style={{ marginTop: 9, fontSize: 11.8, lineHeight: 1.65 }}>{item.description}</p>}
                  <div className="row g6 wrap" style={{ marginTop: 12 }}>
                    <T tone="plain">{t("證據 {n}", { n: displayNumber(item.evidence_count) })}</T>
                    <T tone="plain">{t("涉及 {n} 家公司", { n: displayNumber(item.tenant_count) })}</T>
                  </div>
                  {item.recommendation && <div style={{ marginTop: 13, paddingTop: 11, borderTop: "1px solid var(--hair)", fontSize: 11.8, lineHeight: 1.65 }}>
                    <LB red>{t("建議")}</LB><div style={{ marginTop: 6 }}>{item.recommendation}</div>
                  </div>}
                </article>)}
              </div>}
        </Band>

        <Band no="C" title={t("候選方案")}
          sub={t("每個方案都有狀態、風險與 revision；此頁不直接修改生產秘書。")}>
          {!candidates.length
            ? <EM icon="sparkle" title={t("目前沒有候選方案")}
                sub={t("分析器提出的方案會保存在這裡，等待離線評估與治理。")}/>
            : <div style={{ borderTop: "2px solid var(--rule)" }}>
                {candidates.map((item, index) => <article className="ledger-row" key={item.id} style={{ alignItems: "flex-start" }}>
                  <span className="lr-idx">{String(index + 1).padStart(2, "0")}</span>
                  <div style={{ flex: 1, minWidth: 240 }}>
                    <div className="row g7 wrap">
                      <strong style={{ fontSize: 13.5 }}>{item.title || item.id}</strong>
                      <T tone={statusTone(item.status)} dot>{item.status.toUpperCase()}</T>
                      <T tone={riskTone(item.risk_level)}>{t("風險")} · {item.risk_level.toUpperCase()}</T>
                    </div>
                    {item.hypothesis && <div className="muted" style={{ marginTop: 7, fontSize: 11.5, lineHeight: 1.6 }}>
                      <b>{t("假設")}:</b> {item.hypothesis}
                    </div>}
                    {item.expected_impact && <div style={{ marginTop: 5, fontSize: 11.5, lineHeight: 1.6 }}>
                      <b>{t("預期影響")}:</b> {item.expected_impact}
                    </div>}
                  </div>
                  <div className="mono muted" style={{ fontSize: 9.5, textAlign: "right", lineHeight: 1.7 }}>
                    <div>{t("版本")} · R{item.revision == null ? "—" : item.revision}</div>
                    <div>{t("建立於")} · {timestamp(item.created_at)}</div>
                  </div>
                </article>)}
              </div>}
        </Band>

        <Band no="D" title={t("公司快照帳本")}
          sub={t("每家公司只保存本視窗的聚合計數與可用狀態。")}>
          {!snapshots.length
            ? <EM icon="building" title={t("尚無公司快照")}/>
            : <div style={{ overflowX: "auto", borderTop: "2px solid var(--rule)" }}>
                <table className="tbl2" style={{ minWidth: 1060 }}>
                  <thead><tr>
                    <th>{t("公司")}</th><th>{t("狀態")}</th><th>{t("對話")}</th><th>{t("訊息")}</th>
                    <th>{t("運行")}</th><th>{t("完成")}</th><th>{t("失敗")}</th><th>{t("回饋")}</th>
                    <th>{t("確認")}</th><th>TOKEN</th><th>{t("平均耗時")}</th>
                  </tr></thead>
                  <tbody>{snapshots.map(item => <tr key={item.key}>
                    <td><strong>{item.tenant_name || item.tenant_slug || "—"}</strong>
                      {item.tenant_slug && <div className="mono muted" style={{ fontSize: 9.5 }}>/{item.tenant_slug}</div>}
                    </td>
                    <td>{item.available ? <T tone="ok" dot>{t("可用")}</T> : <T tone="bad">{t("不可用")}</T>}</td>
                    <td className="num">{displayNumber(item.conversation_count)}</td>
                    <td className="num">{displayNumber(item.message_count)}</td>
                    <td className="num">{displayNumber(item.run_count)}</td>
                    <td className="num">{displayNumber(item.completed_run_count)}</td>
                    <td className="num">{displayNumber(item.failed_run_count)}</td>
                    <td className="num">{displayNumber(item.feedback_count)}</td>
                    <td className="num">{displayNumber(item.confirmation_count)}</td>
                    <td className="num">{displayNumber(item.total_tokens)}</td>
                    <td className="mono">{duration(item.avg_duration_ms)}</td>
                  </tr>)}</tbody>
                </table>
              </div>}
        </Band>

        <Band no="E" title={t("分析歷史")}
          sub={t("每次分析都保留聚合規模、發現與候選數量，供平台擁有者追蹤持續迭代。")}>
          {!analysisHistory.length
            ? <EM icon="clock" title={t("尚無分析歷史")}/>
            : <div style={{ overflowX: "auto", borderTop: "2px solid var(--rule)" }}>
                <table className="tbl2" style={{ minWidth: 940 }}>
                  <thead><tr>
                    <th>{t("分析編號")}</th><th>{t("視窗")}</th><th>{t("覆蓋公司")}</th>
                    <th>{t("發現")}</th><th>{t("候選")}</th><th>{t("目標版本")}</th>
                    <th>{t("分析引擎")}</th><th>{t("建立者")}</th><th>{t("建立於")}</th>
                  </tr></thead>
                  <tbody>{analysisHistory.map(item => <tr key={item.key}>
                    <td className="mono">{item.id || "—"}</td>
                    <td className="num">{item.window_days == null ? "—" : t("近 {n} 天", { n: item.window_days })}</td>
                    <td className="num">{displayNumber(item.available_tenant_count)} / {displayNumber(item.tenant_count)}</td>
                    <td className="num">{displayNumber(item.finding_count)}</td>
                    <td className="num">{displayNumber(item.candidate_count)}</td>
                    <td className="mono">{item.objective_version || "—"}</td>
                    <td>{item.analysis_engine || "—"}</td>
                    <td className="mono">{item.created_by_username ? "@" + item.created_by_username : "—"}</td>
                    <td className="mono">{timestamp(item.created_at)}</td>
                  </tr>)}</tbody>
                </table>
              </div>}
        </Band>
      </>}
    </>
  );
};

/* Keep the authority decision outside OptimizerMain so no hook or API effect is
   mounted until /api/auth/me has supplied the authoritative owner flag. */
const Page = ({ isOwner = false }) => isOwner ? <OptimizerMain/> : <Denied/>;
window.W2.PAGES.optimizer = Page;
})();