window.XiaobaiPageModules.register("pools", [
  "limitPool",
  "brokenView",
  "downView",
  "yesterdayView",
  "performanceView",
]);

/* PRESERVATION-SOURCE-BEGIN app.js:1517-1915 */
function getVisibleStocks() {
  if (!state.dashboard) return [];
  let rows = [...(state.dashboard.limits || [])];
  if (state.filter === "1") rows = rows.filter((row) => number(row.streak) === 1);
  if (state.filter === "2") rows = rows.filter((row) => number(row.streak) === 2);
  if (state.filter === "3") rows = rows.filter((row) => number(row.streak) >= 3);
  if (state.query) {
    rows = rows.filter((row) => {
      const haystack = `${row.code} ${row.name} ${row.sector} ${row.reason}`.toLowerCase();
      return haystack.includes(state.query);
    });
  }
  return rows.sort((left, right) => compareRows(left, right));
}

function renderLimitTable() {
  if (!state.dashboard) return;
  const rows = getVisibleStocks();
  const allRows = state.dashboard.limits || [];
  const body = document.querySelector("#limitTableBody");
  body.innerHTML = rows.map((row, index) => `
    <tr data-code="${escapeHtml(row.code)}">
      <td class="row-number num muted">${index + 1}</td>
      <td><span class="stock-cell"><strong class="stock-name sname">${escapeHtml(row.name)}</strong><small class="stock-code scode">${escapeHtml(row.code)}</small></span></td>
      <td class="number num"><span class="pool-streak-tag tag red">${streakLabel(row.streak)}</span></td>
      <td class="number num up">${signed(row.change)}</td>
      <td class="number num">${formatNumber(row.price, 2)}</td>
      <td>${escapeHtml(row.sector || "其他")}</td>
      <td class="number num muted">${escapeHtml(row.first_time || "")}</td>
      <td class="number num muted">${escapeHtml(row.last_time || "")}</td>
      <td class="number num">${limitOpenState(row)}</td>
      <td class="number num">${formatNumber(row.turnover_rate, 2)}</td>
      <td class="number num">${formatNumber(row.amount_billion, 2)}</td>
      <td class="number num">${formatLimitSealAmount(row.seal_amount_million)}</td>
      <td class="pool-reason-cell" title="${escapeHtml(row.reason || "")}">${escapeHtml(row.reason || "")}</td>
    </tr>
  `).join("");
  bindStockRows(body);
  setText("resultCount", `${rows.length} 只`);
  setText("limitPoolSubtitle", `${allRows.length} 只 · 数据日期 ${displayCompactDate(state.dashboard.meta?.trade_date || elements.tradeDate.value)}`);
  setText("limitAllCount", allRows.length);
  setText("limitFirstCount", allRows.filter((row) => number(row.streak) === 1).length);
  setText("limitSecondCount", allRows.filter((row) => number(row.streak) === 2).length);
  setText("limitThreePlusCount", allRows.filter((row) => number(row.streak) >= 3).length);
  document.querySelector("#emptyState").hidden = rows.length !== 0;
  updateSortHeaders();
}

function limitOpenState(row) {
  const openTimes = number(row.open_times);
  const firstTime = String(row.first_time || "");
  if (firstTime.startsWith("09:25") && openTimes === 0) return '<span class="pool-state-tag one-word">一字</span>';
  if (openTimes >= 6) return `<span class="pool-state-tag broken">烂板×${openTimes}</span>`;
  return String(openTimes);
}

function formatLimitSealAmount(value) {
  const amount = number(value);
  if (!amount) return "";
  return Math.round(amount).toLocaleString("zh-CN");
}

function renderBrokenTable(rows) {
  const visibleRows = getVisibleBrokenRows(rows);
  setText("brokenCount", `${rows.length} 只`);
  setText("brokenMeta", ` · 触及涨停后未能封住 · 数据日期 ${displayCompactDate(state.dashboard?.meta?.trade_date || elements.tradeDate.value)}`);
  const body = document.querySelector("#brokenTableBody");
  body.innerHTML = visibleRows.map((row, index) => `
    <tr data-code="${escapeHtml(row.code)}">
      <td class="row-number num muted">${index + 1}</td>
      <td><span class="stock-cell"><strong class="stock-name sname">${escapeHtml(row.name)}</strong><small class="stock-code scode">${escapeHtml(row.code)}</small></span></td>
      <td class="number num ${changeClass(row.change)}" data-sort-value="${number(row.change)}">${signed(row.change)}</td>
      <td class="number num broken-limit-gap" data-sort-value="${row.limitGap}">${formatNumber(row.limitGap, 2)}</td>
      <td class="number num">${formatNumber(row.price, 2)}</td>
      <td>${escapeHtml(row.sector || "其他")}</td>
      <td class="number num muted">${escapeHtml(row.first_time || "")}</td>
      <td class="number num" data-sort-value="${number(row.open_times)}">${brokenOpenState(row)}</td>
      <td class="number num">${formatNumber(row.turnover_rate, 2)}</td>
      <td class="number num">${formatNumber(row.amount_billion, 2)}</td>
      <td class="pool-reason-cell" title="${escapeHtml(row.reason || "")}">${escapeHtml(row.reason || "")}</td>
    </tr>
  `).join("");
  bindStockRows(body);
  document.querySelector("#brokenEmptyState").hidden = visibleRows.length !== 0;
  updateBrokenSortHeaders();
}

function getVisibleBrokenRows(rows = state.dashboard?.broken || []) {
  let visibleRows = rows.map((row) => ({ ...row, limitGap: brokenLimitGap(row) }));
  if (state.brokenQuery) {
    visibleRows = visibleRows.filter((row) => `${row.code} ${row.name} ${row.sector}`.toLowerCase().includes(state.brokenQuery));
  }
  if (!state.brokenSortKey) return visibleRows;
  return visibleRows.sort((left, right) => {
    const result = number(left[state.brokenSortKey]) - number(right[state.brokenSortKey]);
    return state.brokenSortDirection === "asc" ? result : -result;
  });
}

function brokenLimitRate(row) {
  const name = String(row.name || "").toUpperCase();
  const code = String(row.code || "").replace(/\D/g, "");
  if (name.includes("ST")) return 10;
  if (/^(300|301|688|689)/.test(code)) return 20;
  if (/^(4|8|92)/.test(code)) return 30;
  return 10;
}

function brokenLimitGap(row) {
  return Math.max(0, brokenLimitRate(row) - number(row.change));
}

function brokenOpenState(row) {
  const openTimes = number(row.open_times);
  return openTimes >= 6
    ? `<span class="broken-repeat-tag">反复炸 ×${openTimes}</span>`
    : String(openTimes);
}

function changeBrokenSort(key) {
  if (state.brokenSortKey === key) state.brokenSortDirection = state.brokenSortDirection === "asc" ? "desc" : "asc";
  else {
    state.brokenSortKey = key;
    state.brokenSortDirection = "desc";
  }
  renderBrokenTable(state.dashboard?.broken || []);
}

function updateBrokenSortHeaders() {
  document.querySelectorAll("#brokenTable th[data-broken-sort]").forEach((header) => {
    header.classList.remove("sort-asc", "sort-desc", "sorted");
    header.setAttribute("aria-sort", "none");
    if (header.dataset.brokenSort === state.brokenSortKey) {
      header.classList.add(state.brokenSortDirection === "asc" ? "sort-asc" : "sort-desc", "sorted");
      header.setAttribute("aria-sort", state.brokenSortDirection === "asc" ? "ascending" : "descending");
    }
    const arrow = header.querySelector(".arr");
    if (arrow) arrow.textContent = header.classList.contains("sorted") ? (state.brokenSortDirection === "asc" ? "▲" : "▼") : "↕";
  });
}

function renderDownTable(rows) {
  const visibleRows = getVisibleDownRows(rows);
  setText("downCount", `${rows.length} 只`);
  setText("downMeta", ` · 观察退潮、高位风险与亏钱效应 · 数据日期 ${displayCompactDate(state.dashboard?.meta?.trade_date || elements.tradeDate.value)}`);
  renderDownSectorCluster(rows);
  const body = document.querySelector("#downTableBody");
  body.innerHTML = visibleRows.map((row, index) => `
    <tr data-code="${escapeHtml(row.code)}">
      <td class="row-number num muted">${index + 1}</td>
      <td><span class="stock-cell"><strong class="stock-name sname">${escapeHtml(row.name)}</strong><small class="stock-code scode">${escapeHtml(row.code)}</small></span></td>
      <td class="number num down" data-sort-value="${number(row.change)}">${signed(row.change)}</td>
      <td class="number num">${formatNumber(row.price, 2)}</td>
      <td>${escapeHtml(row.sector || "其他")}</td>
      <td class="number num">${formatNumber(row.turnover_rate, 2)}</td>
      <td class="number num">${formatNumber(row.amount_billion, 2)}</td>
      <td class="number num">${number(row.streak) > 0 ? number(row.streak) : ""}</td>
      <td class="pool-reason-cell" title="${escapeHtml(row.reason || "")}">${escapeHtml(row.reason || "")}</td>
    </tr>
  `).join("");
  bindStockRows(body);
  document.querySelector("#downEmptyState").hidden = visibleRows.length !== 0;
  updateDownSortHeaders();
}

function getVisibleDownRows(rows = state.dashboard?.down_limits || []) {
  let visibleRows = [...rows];
  if (state.downQuery) {
    visibleRows = visibleRows.filter((row) => `${row.code} ${row.name} ${row.sector}`.toLowerCase().includes(state.downQuery));
  }
  if (!state.downSortKey) return visibleRows;
  return visibleRows.sort((left, right) => {
    const result = number(left[state.downSortKey]) - number(right[state.downSortKey]);
    return state.downSortDirection === "asc" ? result : -result;
  });
}

function renderDownSectorCluster(rows) {
  const counts = new Map();
  rows.forEach((row) => {
    const sector = String(row.sector || "其他").trim() || "其他";
    if (sector === "其他") return;
    counts.set(sector, (counts.get(sector) || 0) + 1);
  });
  const cluster = [...counts.entries()].sort((left, right) => right[1] - left[1])[0];
  const element = document.querySelector("#downSectorCluster");
  element.hidden = !cluster || cluster[1] < 2;
  element.textContent = cluster && cluster[1] >= 2 ? `${cluster[0]}集中跌停 ×${cluster[1]}` : "";
}

function changeDownSort(key) {
  if (state.downSortKey === key) state.downSortDirection = state.downSortDirection === "asc" ? "desc" : "asc";
  else {
    state.downSortKey = key;
    state.downSortDirection = "asc";
  }
  renderDownTable(state.dashboard?.down_limits || []);
}

function updateDownSortHeaders() {
  document.querySelectorAll("#downTable th[data-down-sort]").forEach((header) => {
    header.classList.remove("sort-asc", "sort-desc", "sorted");
    header.setAttribute("aria-sort", "none");
    if (header.dataset.downSort === state.downSortKey) {
      header.classList.add(state.downSortDirection === "asc" ? "sort-asc" : "sort-desc", "sorted");
      header.setAttribute("aria-sort", state.downSortDirection === "asc" ? "ascending" : "descending");
    }
    const arrow = header.querySelector(".arr");
    if (arrow) arrow.textContent = header.classList.contains("sorted") ? (state.downSortDirection === "asc" ? "▲" : "▼") : "↕";
  });
}

function renderYesterdayTable(rows) {
  const visibleRows = getVisibleYesterdayRows(rows);
  const currentDate = displayCompactDate(state.dashboard?.meta?.trade_date || elements.tradeDate.value);
  const previousDate = displayCompactDate(state.dashboard?.meta?.previous_trade_date || "");
  setText("yesterdayCount", `${rows.length} 只`);
  setText("yesterdayMeta", ` · 昨日 ${previousDate} → 今日 ${currentDate}`);
  renderYesterdaySummary(rows);
  const body = document.querySelector("#yesterdayTableBody");
  body.innerHTML = visibleRows.map((row, index) => `
    <tr data-code="${escapeHtml(row.code)}">
      <td class="row-number num muted">${index + 1}</td>
      <td><span class="stock-cell"><strong class="stock-name sname">${escapeHtml(row.name)}</strong><small class="stock-code scode">${escapeHtml(row.code)}</small></span></td>
      <td class="number num">${number(row.prior_streak)}</td>
      <td class="number num ${changeClass(row.current_change)}">${signed(row.current_change)}</td>
      <td><span class="yesterday-outcome-tag ${yesterdayOutcomeClass(row.outcome)}">${escapeHtml(row.outcome)}</span></td>
      <td class="number num">${number(row.current_streak) ? `<span class="yesterday-height-tag">${number(row.current_streak)}</span>` : ""}</td>
      <td>${escapeHtml(row.sector || "其他")}</td>
      <td class="pool-reason-cell" title="${escapeHtml(row.reason || "")}">${escapeHtml(row.reason || "")}</td>
    </tr>
  `).join("");
  bindStockRows(body);
  document.querySelector("#yesterdayEmptyState").hidden = visibleRows.length !== 0;
  updateYesterdayControls();
}

function getVisibleYesterdayRows(rows = state.dashboard?.yesterday_limits || []) {
  let visibleRows = rows.filter((row) => {
    if (state.yesterdayFilter === "advance") return row.outcome === "晋级";
    if (state.yesterdayFilter === "positive") return number(row.current_change) > 0;
    if (state.yesterdayFilter === "fail") return row.outcome === "断板";
    if (state.yesterdayFilter === "risk") return ["炸板", "跌停"].includes(row.outcome);
    return true;
  });
  if (state.yesterdayQuery) {
    visibleRows = visibleRows.filter((row) => `${row.code} ${row.name} ${row.sector}`.toLowerCase().includes(state.yesterdayQuery));
  }
  if (!state.yesterdaySortKey) return visibleRows;
  return visibleRows.sort((left, right) => {
    const result = number(left[state.yesterdaySortKey]) - number(right[state.yesterdaySortKey]);
    return state.yesterdaySortDirection === "asc" ? result : -result;
  });
}

function renderYesterdaySummary(rows) {
  const total = rows.length;
  const advance = rows.filter((row) => row.outcome === "晋级").length;
  const positive = rows.filter((row) => number(row.current_change) > 0).length;
  const fail = rows.filter((row) => row.outcome === "断板").length;
  const risk = rows.filter((row) => ["炸板", "跌停"].includes(row.outcome)).length;
  const rate = (value) => total ? value / total * 100 : 0;
  setText("yesterdayAllCount", total);
  setText("yesterdayAdvanceCount", advance);
  setText("yesterdayAdvanceRate", `晋级率 ${formatNumber(rate(advance), 1)}%`);
  setText("yesterdayPositiveCount", positive);
  setText("yesterdayPositiveRate", `兑现率 ${formatNumber(rate(positive), 1)}%`);
  setText("yesterdayFailCount", fail);
  setText("yesterdayFailRate", `占 ${formatNumber(rate(fail), 1)}%`);
  setText("yesterdayRiskCount", risk);
  setText("yesterdayRiskRate", `亏钱效应 ${formatNumber(rate(risk), 1)}%`);
}

function yesterdayOutcomeClass(outcome) {
  return { "晋级": "advance", "断板": "fail", "炸板": "broken", "跌停": "down" }[outcome] || "fail";
}

function changeYesterdaySort(key) {
  if (state.yesterdaySortKey === key) state.yesterdaySortDirection = state.yesterdaySortDirection === "asc" ? "desc" : "asc";
  else {
    state.yesterdaySortKey = key;
    state.yesterdaySortDirection = "desc";
  }
  renderYesterdayTable(state.dashboard?.yesterday_limits || []);
}

function updateYesterdayControls() {
  document.querySelectorAll("[data-yesterday-filter]").forEach((button) => {
    const active = button.dataset.yesterdayFilter === state.yesterdayFilter;
    button.classList.toggle("active", active);
    button.setAttribute("aria-pressed", String(active));
  });
  document.querySelectorAll("#yesterdayTable th[data-yesterday-sort]").forEach((header) => {
    header.classList.remove("sort-asc", "sort-desc", "sorted");
    header.setAttribute("aria-sort", "none");
    if (header.dataset.yesterdaySort === state.yesterdaySortKey) {
      header.classList.add(state.yesterdaySortDirection === "asc" ? "sort-asc" : "sort-desc", "sorted");
      header.setAttribute("aria-sort", state.yesterdaySortDirection === "asc" ? "ascending" : "descending");
    }
    const arrow = header.querySelector(".arr");
    if (arrow) arrow.textContent = header.classList.contains("sorted") ? (state.yesterdaySortDirection === "asc" ? "▲" : "▼") : "↕";
  });
}

function renderPerformance(rows) {
  rows = normalizePerformanceRows(rows);
  const currentDate = displayCompactDate(state.dashboard?.meta?.trade_date || elements.tradeDate.value);
  const previousDate = displayCompactDate(state.dashboard?.meta?.previous_trade_date || "");
  setText("performanceDateRange", `昨日 ${previousDate} → 今日 ${currentDate}`);
  document.querySelector("#performanceCards").innerHTML = rows.map((row) => `
    <article class="performance-stage-card" title="收红 ${formatNumber(row.positive_rate, 1)}% · 平均涨幅 ${signed(row.average_change)}%"
      aria-label="${escapeHtml(row.label)}，晋级率 ${formatNumber(row.advance_rate, 1)}%，晋级 ${number(row.advanced)} 只，共 ${number(row.count)} 只，收红率 ${formatNumber(row.positive_rate, 1)}%，平均涨幅 ${signed(row.average_change)}%">
      <div class="performance-stage-label"><span>${escapeHtml(row.label)} → 今日</span><i class="performance-status-tag ${performanceRateState(row.advance_rate).className}">${performanceRateState(row.advance_rate).label}</i></div>
      <strong class="performance-stage-rate ${performanceRateState(row.advance_rate).className}">${formatNumber(row.advance_rate, 1)}%</strong>
      <span class="performance-stage-count">晋级 ${number(row.advanced)} / 共 ${number(row.count)} 只</span>
      <div class="performance-stage-track" aria-hidden="true"><i class="${performanceRateState(row.advance_rate).className}" style="width:${Math.max(number(row.advance_rate), number(row.advance_rate) > 0 ? 2 : 0)}%"></i></div>
    </article>
  `).join("") || '<div class="performance-empty-state">暂无昨日涨停统计</div>';
  renderPerformanceConclusion(rows);
  renderMarketBreadth(state.dashboard?.overview || {});
}

function normalizePerformanceRows(rows) {
  const groups = new Map();
  (rows || []).forEach((row) => {
    const level = Math.max(1, number(row.level));
    const displayLevel = Math.min(level, 5);
    const group = groups.get(displayLevel) || {
      level: displayLevel,
      label: displayLevel === 1 ? "昨日首板" : displayLevel === 5 ? "昨日5板+" : `昨日${displayLevel}板`,
      count: 0,
      advanced: 0,
      positive: 0,
      changeTotal: 0,
    };
    const count = number(row.count);
    group.count += count;
    group.advanced += number(row.advanced);
    group.positive += count * number(row.positive_rate) / 100;
    group.changeTotal += count * number(row.average_change);
    groups.set(displayLevel, group);
  });
  return [...groups.values()]
    .sort((left, right) => right.level - left.level)
    .map((group) => ({
      level: group.level,
      label: group.label,
      count: group.count,
      advanced: group.advanced,
      advance_rate: group.count ? group.advanced / group.count * 100 : 0,
      positive_rate: group.count ? group.positive / group.count * 100 : 0,
      average_change: group.count ? group.changeTotal / group.count : 0,
    }));
}

function performanceRateState(rate) {
  const value = number(rate);
  if (value === 0) return { label: "失效", className: "is-neutral" };
  if (value < 20) return { label: "危险", className: "is-warning" };
  return { label: "活跃", className: "is-active" };
}

function renderPerformanceConclusion(rows) {
  const container = document.querySelector("#performanceConclusion");
  if (!rows.length) {
    container.innerHTML = '<div class="empty-state">暂无昨日梯队数据，暂不生成结论</div>';
    return;
  }
  const sorted = [...rows].sort((left, right) => number(right.level) - number(left.level));
  const highRows = sorted.filter((row) => number(row.level) >= 4);
  const highAdvanced = highRows.reduce((total, row) => total + number(row.advanced), 0);
  const highSamples = highRows.map((row) => escapeHtml(row.label)).join("、");
  const strongest = [...rows].sort((left, right) => (
    number(right.advance_rate) - number(left.advance_rate) || number(right.level) - number(left.level)
  ))[0];
  const firstBoard = rows.find((row) => number(row.level) === 1);
  const overview = state.dashboard?.overview || {};
  const phase = overview.sentiment_phase || "观察";
  const up = number(overview.up_count);
  const down = number(overview.down_count);
  const breadthRate = up + down > 0 ? up / (up + down) * 100 : 50;
  const stance = breadthRate < 25 ? "宜守不宜攻" : breadthRate < 45 ? "控制仓位，聚焦核心" : "保持精选，跟随强势梯队";
  const highText = highRows.length
    ? `高位晋级率<b class="${highAdvanced ? "up" : "is-neutral"}">${highAdvanced ? "仍有承接" : "全线失效"}</b>：${highSamples}${highAdvanced ? `共晋级 ${highAdvanced} 只` : "今日均未晋级"}；`
    : "高位梯队暂无昨日样本，空间信号仍待确认；";
  const strongestText = strongest
    ? `<b>${escapeHtml(strongest.label)}</b>晋级率最高，为 <b class="up">${formatNumber(strongest.advance_rate, 1)}%</b>（${number(strongest.advanced)} 只晋级 / 共 ${number(strongest.count)} 只）；`
    : "暂无相对占优梯队；";
  const firstBoardText = firstBoard
    ? `首板基数 ${number(firstBoard.count)} 只，晋级率 <b class="${performanceRateState(firstBoard.advance_rate).className}">${formatNumber(firstBoard.advance_rate, 1)}%</b>，低位接力${number(firstBoard.advance_rate) < 20 ? "胜率偏低" : "仍有活跃度"}；`
    : "首板梯队暂无有效样本；";
  container.innerHTML = `
    <div>· ${highText}</div>
    <div>· ${strongestText}</div>
    <div>· ${firstBoardText}</div>
    <div>· 结论：<b>${stance}</b>，当前情绪周期「${escapeHtml(phase)}」。</div>
  `;
}

/* PRESERVATION-SOURCE-END app.js:1517-1915 */
