<script setup lang="ts">
import { computed, reactive, ref } from "vue";

import type { MarketWorkspaceData } from "../../../shared/api/market";
import MarketEntityLink from "../../../shared/market/MarketEntityLink.vue";

const props = defineProps<{ data: MarketWorkspaceData }>();
const sortMode = ref<"time" | "open">("time");
const expanded = reactive(new Set<number>());
const sourceGroups = computed(() => props.data.items ?? []);
const maxLevel = computed(() => Math.max(0, ...sourceGroups.value.map((group) => Number(group.level ?? 0))));
const topLevel = computed(() => Math.max(5, maxLevel.value));
const groups = computed(() => {
  const byLevel = new Map(sourceGroups.value.map((group) => [Number(group.level), group]));
  const normalized = Array.from({ length: topLevel.value }, (_, index) => {
    const level = topLevel.value - index;
    const source = byLevel.get(level) ?? { level, label: level === 1 ? "首板" : `${level}板`, count: 0, stocks: [] };
    const stocks = [...((source.stocks as Record<string, unknown>[] | undefined) ?? [])].sort((left, right) => {
      if (sortMode.value === "open") {
        return Number(left.open_times ?? 0) - Number(right.open_times ?? 0)
          || String(left.first_time ?? "99:99").localeCompare(String(right.first_time ?? "99:99"));
      }
      return String(left.first_time ?? "99:99").localeCompare(String(right.first_time ?? "99:99"));
    });
    const limit = level <= 2 ? 8 : stocks.length;
    return {
      level,
      label: String(source.label ?? (level === 1 ? "首板" : `${level}板`)),
      count: Number(source.count ?? stocks.length),
      stocks,
      visible: expanded.has(level) ? stocks : stocks.slice(0, limit),
      hidden: Math.max(0, stocks.length - limit),
    };
  });
  return normalized.map((group) => {
    const lower = normalized.find((item) => item.level === group.level - 1);
    return {
      ...group,
      adjacentRate: lower?.count ? group.count / lower.count * 100 : null,
    };
  });
});
const completeness = computed(() => maxLevel.value
  ? sourceGroups.value.filter((group) => Number(group.count ?? 0) > 0).length / maxLevel.value * 100
  : 0);
const priorPerformance = computed(() => props.data.history ?? []);
const priorHeight = computed(() => Math.max(0, ...priorPerformance.value.map((row) => Number(row.level ?? 0))));
const heightMessage = computed(() => {
  if (!maxLevel.value) return "当前没有连板梯队。";
  if (!priorPerformance.value.length) return "暂无昨日梯队样本，先观察当前结构。";
  if (maxLevel.value > priorHeight.value) return `较昨日${priorHeight.value}板抬升，市场空间打开。`;
  if (maxLevel.value < priorHeight.value) return `较昨日${priorHeight.value}板回落，市场空间压缩。`;
  return "市场高度与昨日接近，继续观察梯队承接。";
});

function toggle(level: number): void {
  if (expanded.has(level)) expanded.delete(level);
  else expanded.add(level);
}

function exportCsv(): void {
  const lines = [["高度", "代码", "股票", "板块", "首封", "开板次数", "成交额（亿）"]];
  for (const group of groups.value) {
    for (const stock of group.stocks) {
      lines.push([
        `${group.level}板`, String(stock.code ?? ""), String(stock.name ?? ""),
        String(stock.sector ?? ""), String(stock.first_time ?? ""), String(stock.open_times ?? ""),
        (Number(stock.amount ?? 0) / 100_000_000).toFixed(2),
      ]);
    }
  }
  const content = lines.map((line) => line.map((value) => `"${value.replaceAll('"', '""')}"`).join(",")).join("\r\n");
  const link = document.createElement("a");
  link.href = URL.createObjectURL(new Blob(["\ufeff", content], { type: "text/csv;charset=utf-8" }));
  link.download = `市场天梯-${props.data.trade_date}.csv`;
  link.click();
  URL.revokeObjectURL(link.href);
}
</script>

<template>
  <header class="page-header market-page-header">
    <div><h1>市场天梯</h1><p class="page-subtitle">按连板高度观察空间与梯队完整度 · 数据日期 {{ data.trade_date }}</p></div>
    <div class="page-actions"><div class="seg-control"><button type="button" :class="{ active: sortMode === 'time' }" @click="sortMode = 'time'">按封板时间</button><button type="button" :class="{ active: sortMode === 'open' }" @click="sortMode = 'open'">按开板次数</button></div><button class="btn btn-small" type="button" @click="exportCsv">导出 CSV</button></div>
  </header>
  <section class="ladder-layout">
    <div class="card ladder-board">
      <section v-for="group in groups" :key="group.level" class="ladder-level" :class="{ 'is-gap': !Number(group.count) }">
        <header><div><strong>{{ group.level === 1 ? "首板" : `${group.level}板` }}</strong><span>{{ group.count }}只</span></div><small v-if="group.level > 1 && Number(group.count)">{{ group.adjacentRate === null ? "相邻梯队断层" : `相邻梯队 ${group.adjacentRate.toFixed(1)}%` }}</small></header>
        <div class="ladder-stocks">
          <article v-for="stock in group.visible" :key="String(stock.identifier)" class="ladder-stock">
            <div><strong>{{ stock.name }}</strong><MarketEntityLink v-if="stock.identifier" :entity="{ entity_type: 'stock', identifier: String(stock.identifier), code: String(stock.code), name: String(stock.name), sector: stock.sector ? String(stock.sector) : null }" /></div>
            <p><b>{{ stock.sector || "其他" }}</b><span>{{ stock.first_time || "时间待校正" }}</span></p>
            <small>开板 {{ stock.open_times }}次 · 成交 {{ (Number(stock.amount ?? 0) / 100_000_000).toFixed(2) }}亿</small>
          </article>
          <p v-if="!group.visible.length" class="ladder-gap-note">该层暂时空缺</p>
          <button v-if="group.stocks.length > 8 && group.level <= 2" class="ladder-expand" type="button" @click="toggle(group.level)">{{ expanded.has(group.level) ? "收起" : `展开更多（${group.hidden}）` }}</button>
        </div>
      </section>
    </div>
    <aside class="ladder-insights">
      <article class="card"><header class="card-header"><h2>市场高度</h2></header><div class="ladder-insight-body"><strong>{{ maxLevel ? `${maxLevel}板` : "--" }}</strong><p>{{ heightMessage }}</p></div></article>
      <article class="card"><header class="card-header"><h2>梯队完整度</h2></header><div class="ladder-insight-body"><strong>{{ completeness.toFixed(1) }}%</strong><div class="score-track"><span :style="{ width: `${completeness}%` }"></span></div><p>从首板到最高板之间存在的真实高度比例。</p></div></article>
      <article class="card"><header class="card-header"><h2>昨日梯队 → 今日</h2></header><div class="ladder-rate-list"><div v-for="row in priorPerformance" :key="String(row.level)"><span>昨日{{ row.level }}板</span><div class="score-track"><span :style="{ width: `${row.advance_rate}%` }"></span></div><strong>{{ row.advance_rate }}%</strong></div></div></article>
    </aside>
  </section>
</template>
