"use client";

import { useEffect, useState, useCallback, useMemo } from "react";
import { fetchAPI } from "@/lib/api";
import type { SectorData, LeadingStock, SectorRotationData } from "@/lib/api";
import { formatNumber } from "@/lib/utils";
import { useWebSocket } from "@/hooks/use-websocket";
import { ErrorBoundary } from "@/components/error-boundary";

function getStageInfo(stage: string) {
  switch (stage) {
    case "early":
      return { label: "启动期", color: "text-emerald-400", bg: "bg-emerald-500/10 border-emerald-500/15", barColor: "bg-emerald-500/60" };
    case "mid":
      return { label: "发展期", color: "text-amber-400", bg: "bg-amber-500/10 border-amber-500/15", barColor: "bg-amber-500/60" };
    case "late":
      return { label: "后期", color: "text-orange-400", bg: "bg-orange-500/10 border-orange-500/15", barColor: "bg-orange-500/60" };
    case "end":
      return { label: "尾声", color: "text-red-400", bg: "bg-red-500/10 border-red-500/15", barColor: "bg-red-500/60" };
    default:
      return { label: "—", color: "text-text-muted", bg: "bg-surface-2 border-border-default", barColor: "bg-surface-3" };
  }
}

function getOpportunityHint(stage: string, mainForceRatio?: number): string {
  switch (stage) {
    case "early": return "关注启动强度";
    case "mid": return (mainForceRatio ?? 0) > 30 ? "关注回流确认" : "观察资金动向";
    case "late": return "注意高位分化";
    case "end": return "以观望为主";
    default: return "";
  }
}

function normalizeValues(values: number[]): number[] {
  if (!values.length) return [];
  const min = Math.min(...values);
  const max = Math.max(...values);
  if (max === min) return values.map(() => 50);
  return values.map(v => (v - min) / (max - min) * 100);
}

/** 迷你柱状图：近5日涨跌幅 */
function MiniBarChart({ data }: { data: number[] }) {
  if (!data.length) return null;
  const maxAbs = Math.max(...data.map(Math.abs), 0.1);
  return (
    <div className="flex items-end gap-1 h-8">
      {data.map((v, i) => {
        const h = Math.max(Math.abs(v) / maxAbs * 100, 8);
        return (
          <div key={i} className="flex-1 flex flex-col justify-end items-center" style={{ height: "100%" }}>
            <div
              className={`w-full rounded-sm transition-all duration-300 ${v >= 0 ? "bg-red-500/50" : "bg-emerald-500/50"}`}
              style={{ height: `${h}%` }}
            />
          </div>
        );
      })}
    </div>
  );
}

/** 领涨股标签 */
function LeadingStockTag({ stock }: { stock: LeadingStock }) {
  const isLimitUp = stock.pct_chg >= 9.8;
  return (
    <a
      href={`/stock/${stock.ts_code}`}
      className="inline-flex items-center gap-1 text-[11px] px-2 py-1 rounded-lg bg-surface-2 border border-border-default hover:bg-surface-4 transition-colors"
    >
      <span className="text-text-secondary font-medium">{stock.name}</span>
      <span className={`font-mono tabular-nums ${isLimitUp ? "text-red-400 font-bold" : stock.pct_chg > 0 ? "text-red-400/80" : "text-emerald-400/80"}`}>
        {stock.pct_chg > 0 ? "+" : ""}{stock.pct_chg}%
      </span>
      {stock.limit_times != null && stock.limit_times > 1 && (
        <span className="text-[9px] px-1 py-0.5 rounded bg-red-500/15 text-red-400 font-bold">
          {stock.limit_times}连板
        </span>
      )}
    </a>
  );
}

function HeatScoreDots({ scores: [pct, cap, lim, con] }: { scores: [number, number, number, number] }) {
  const dots = [
    { score: pct, label: "涨幅" },
    { score: cap, label: "资金" },
    { score: lim, label: "涨停" },
    { score: con, label: "连续" },
  ];
  return (
    <div className="flex items-center gap-1">
      {dots.map((d) => (
        <span
          key={d.label}
          className={`w-1.5 h-1.5 rounded-full ${d.score >= 60 ? "bg-amber-400" : "bg-text-muted/30"}`}
          title={`${d.label}因子: ${d.score.toFixed(0)}`}
        />
      ))}
    </div>
  );
}

function SectorDetailCard({ sector, index, factorScores }: {
  sector: SectorData;
  index: number;
  factorScores?: [number, number, number, number];
}) {
  const displayPct = sector.realtime_pct_change ?? sector.pct_change;
  const isUp = displayPct > 0;
  const displayLimitUp = sector.realtime_limit_up_count ?? sector.limit_up_count;
  const displayAmount = sector.realtime_amount ?? sector.capital_inflow;
  const displayTurnover = sector.realtime_turnover_rate ?? sector.turnover_avg ?? 0;
  const displayUpCount = sector.realtime_up_count;
  const displayDownCount = sector.realtime_down_count;
  const leaders = sector.is_realtime
    ? (sector.leading_stocks_realtime?.length ? sector.leading_stocks_realtime : sector.leading_stocks)
    : sector.leading_stocks;
  const stage = getStageInfo(sector.stage ?? "");
  const isTop3 = index < 3;
  const cumulativePct = sector.pct_trend ? sector.pct_trend.reduce((sum, v) => sum + v, 0) : sector.pct_change;
  const hint = getOpportunityHint(sector.stage ?? "", sector.main_force_ratio);
  const mainForceRatio = sector.main_force_ratio ?? 0;

  return (
    <div
      className="glass-card animate-fade-in-up overflow-hidden"
      style={{ animationDelay: `${index * 60}ms` }}
    >
      {/* Stage color bar at top */}
      <div className={`h-1 ${stage.barColor}`} />

      <div className="p-5">
        {/* Header row */}
        <div className="flex items-start justify-between mb-2">
          <div className="flex items-center gap-2.5">
            <span className={`w-7 h-7 rounded-lg flex items-center justify-center text-xs font-bold shrink-0 ${
              index === 0
                ? "bg-gradient-to-br from-amber-500/30 to-amber-600/20 text-amber-400 border border-amber-500/20"
                : index === 1
                ? "bg-gradient-to-br from-slate-400/20 to-slate-500/15 text-slate-300 border border-slate-400/15"
                : index === 2
                ? "bg-gradient-to-br from-amber-700/20 to-amber-800/15 text-amber-400 border border-amber-600/15"
                : "bg-surface-2 text-text-muted border border-border-subtle"
            }`}>
              {index + 1}
            </span>
            <div>
              <div className="flex items-center gap-2">
                <span className={`text-sm font-semibold ${isTop3 ? "text-text-primary" : "text-text-secondary"}`}>
                  {sector.sector_name}
                </span>
                {sector.is_realtime && (
                  <span className="text-[9px] px-1.5 py-0.5 rounded bg-emerald-500/10 text-emerald-400/80 border border-emerald-500/15">
                    实时
                  </span>
                )}
              </div>
              <div className="text-[11px] text-text-muted/60 mt-0.5">
                {stage.label !== "—" && (
                  <>
                    <span className={stage.color}>{stage.label}</span>
                    <span className="text-text-muted/30 mx-1">·</span>
                    <span>连{sector.days_continuous}天</span>
                    <span className="text-text-muted/30 mx-1">·</span>
                    <span className={`font-mono tabular-nums ${cumulativePct > 0 ? "text-red-400/60" : "text-emerald-400/60"}`}>
                      累计{cumulativePct > 0 ? "+" : ""}{cumulativePct.toFixed(1)}%
                    </span>
                  </>
                )}
                {stage.label === "—" && sector.member_count && `${sector.member_count}只成分股`}
              </div>
            </div>
          </div>
          <div className="text-right">
            <div className={`text-base font-bold font-mono tabular-nums ${isUp ? "text-red-400" : "text-emerald-400"}`}>
              {displayPct > 0 ? "+" : ""}{displayPct.toFixed(2)}%
            </div>
          </div>
        </div>

        {/* Opportunity hint */}
        {hint && (
          <div className={`text-[11px] mb-3 px-2.5 py-1.5 rounded-lg ${stage.bg} ${stage.color}`}>
            {hint}
          </div>
        )}

        {/* Metrics row - 4 columns */}
        <div className="grid grid-cols-4 gap-2 mb-3">
          <div className="bg-surface-1 rounded-lg px-2.5 py-2">
            <div className="text-[10px] text-text-muted/50 mb-0.5">{sector.is_realtime ? "实时成交额" : "资金净流入"}</div>
            <div className={`text-xs font-mono tabular-nums font-semibold ${displayAmount > 0 ? "text-red-400" : "text-emerald-400"}`}>
              {displayAmount > 0 ? "+" : ""}{formatNumber(displayAmount)}
            </div>
          </div>
          <div className="bg-surface-1 rounded-lg px-2.5 py-2">
            <div className="text-[10px] text-text-muted/50 mb-0.5">{sector.is_realtime ? "上涨/下跌" : "涨停股"}</div>
            {sector.is_realtime && displayUpCount != null && displayDownCount != null ? (
              <div className="text-xs font-mono tabular-nums font-semibold text-text-secondary">
                {displayUpCount}<span className="text-text-muted/40 text-[10px]"> / </span>{displayDownCount}
              </div>
            ) : (
              <div className="text-xs font-mono tabular-nums font-semibold text-text-secondary">
                {displayLimitUp}<span className="text-text-muted/40 text-[10px]"> 只</span>
              </div>
            )}
          </div>
          <div className="bg-surface-1 rounded-lg px-2.5 py-2">
            <div className="text-[10px] text-text-muted/50 mb-0.5">{sector.is_realtime ? "实时换手" : "主力占比"}</div>
            {sector.is_realtime ? (
              <div className="text-xs font-mono tabular-nums font-semibold text-text-secondary">
                {displayTurnover.toFixed(1)}<span className="text-text-muted/40 text-[10px]">%</span>
              </div>
            ) : (
              <div className={`text-xs font-mono tabular-nums font-semibold ${
                mainForceRatio > 30 ? "text-amber-400" : mainForceRatio < 0 ? "text-red-400" : "text-text-secondary"
              }`}>
                {mainForceRatio.toFixed(1)}<span className="text-text-muted/40 text-[10px]">%</span>
              </div>
            )}
          </div>
          <div className="bg-surface-1 rounded-lg px-2.5 py-2">
            <div className="text-[10px] text-text-muted/50 mb-0.5">热度评分</div>
            <div className="flex items-center gap-1.5">
              <span className={`text-xs font-mono tabular-nums font-semibold ${
                sector.heat_score >= 70 ? "text-amber-400" : sector.heat_score >= 50 ? "text-text-secondary" : "text-text-muted"
              }`}>
                {sector.heat_score.toFixed(0)}
                <span className="text-text-muted/40 text-[10px]">/100</span>
              </span>
              {factorScores && <HeatScoreDots scores={factorScores} />}
            </div>
          </div>
        </div>

        {/* 5日趋势图 */}
        {sector.pct_trend && sector.pct_trend.length > 1 && (
          <div className="mb-3">
            <div className="flex items-center justify-between mb-1.5">
              <span className="text-[10px] text-text-muted/50">近5日走势</span>
              <div className="flex gap-2">
                {sector.pct_trend.map((v, i) => (
                  <span key={i} className={`text-[9px] font-mono tabular-nums ${v >= 0 ? "text-red-400/60" : "text-emerald-400/60"}`}>
                    {v > 0 ? "+" : ""}{v.toFixed(1)}
                  </span>
                ))}
              </div>
            </div>
            <MiniBarChart data={sector.pct_trend} />
          </div>
        )}

        {/* 领涨股 */}
        {leaders && leaders.length > 0 && (
          <div>
            <span className="text-[10px] text-text-muted/50 mb-1.5 block">领涨股</span>
            <div className="flex flex-wrap gap-1.5">
              {leaders.map((s) => (
                <LeadingStockTag key={s.ts_code} stock={s} />
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

/** 今日关注 - Top 3 摘要 */
function FocusSummary({ sectors }: { sectors: SectorData[] }) {
  const top3 = sectors.slice(0, 3);
  if (!top3.length) return null;

  return (
    <div className="glass-card-static p-4 animate-fade-in-up mb-4">
      <h2 className="text-xs font-semibold text-amber-400 uppercase tracking-wider mb-3">
        今日关注
      </h2>
      <div className="grid grid-cols-1 md:grid-cols-3 xl:grid-cols-1 gap-3">
        {top3.map((sector, i) => {
          const displayPct = sector.realtime_pct_change ?? sector.pct_change;
          const isUp = displayPct > 0;
          const stage = getStageInfo(sector.stage ?? "");
          const hint = getOpportunityHint(sector.stage ?? "", sector.main_force_ratio);
          const mainForceRatio = sector.main_force_ratio ?? 0;

          return (
            <div key={sector.sector_code} className={`rounded-xl p-3 border ${stage.bg}`}>
              <div className="flex flex-wrap items-start justify-between gap-2 mb-1.5">
                <div className="flex min-w-0 items-center gap-2">
                  <span className={`w-5 h-5 rounded-md flex items-center justify-center text-[10px] font-bold ${
                    i === 0 ? "bg-amber-500/20 text-amber-400" : i === 1 ? "bg-slate-400/15 text-slate-300" : "bg-amber-700/15 text-amber-400/80"
                  }`}>
                    {i + 1}
                  </span>
                  <span className="min-w-0 break-words text-sm font-semibold text-text-primary">
                    {sector.sector_name}
                  </span>
                </div>
                <div className="ml-auto flex shrink-0 flex-wrap items-center justify-end gap-1.5">
                  <span className={`text-[10px] px-1.5 py-0.5 rounded-md border font-medium ${stage.bg} ${stage.color}`}>
                    {stage.label}
                  </span>
                  <span className={`text-sm font-bold font-mono tabular-nums ${isUp ? "text-red-400" : "text-emerald-400"}`}>
                    {displayPct > 0 ? "+" : ""}{displayPct.toFixed(2)}%
                  </span>
                </div>
              </div>
              <div className={`text-[11px] ${stage.color} mb-2`}>
                {hint}
              </div>
              <div className="flex flex-wrap items-center gap-x-3 gap-y-1.5 text-[11px]">
                <span className={`font-mono tabular-nums ${sector.capital_inflow > 0 ? "text-red-400/80" : "text-emerald-400/80"}`}>
                  资金{sector.capital_inflow > 0 ? "+" : ""}{formatNumber(sector.capital_inflow)}
                </span>
                {mainForceRatio !== 0 && (
                  <span className={`font-mono tabular-nums ${mainForceRatio > 30 ? "text-amber-400/80" : "text-text-muted/60"}`}>
                    主力{mainForceRatio.toFixed(1)}%
                  </span>
                )}
                {(sector.realtime_limit_up_count ?? sector.limit_up_count) > 0 && (
                  <span className="font-mono tabular-nums text-red-400/80">
                    涨停{(sector.realtime_limit_up_count ?? sector.limit_up_count)}只
                  </span>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

export default function SectorsPage() {
  const [sectors, setSectors] = useState<SectorData[]>([]);
  const [showRotation, setShowRotation] = useState(false);
  const [rotationData, setRotationData] = useState<SectorRotationData | null>(null);
  const [stageFilter, setStageFilter] = useState<string>("all");

  const loadData = useCallback(async () => {
    try {
      const data = await fetchAPI<SectorData[]>("/api/sectors/hot?limit=20");
      setSectors(data);
    } catch {
      // ignore
    }
  }, []);

  useEffect(() => {
    loadData();
  }, [loadData]);

  useWebSocket(
    useCallback(() => {
      loadData();
    }, [loadData])
  );

  const hasRealtime = sectors.some((s) => s.is_realtime);
  const structureTradeDate = sectors[0]?.structure_trade_date || sectors[0]?.trade_date || "";
  const dataMode = sectors[0]?.data_mode || "daily_snapshot";

  const loadRotation = useCallback(async () => {
    try {
      const data = await fetchAPI<SectorRotationData>("/api/sectors/rotation?days=5");
      setRotationData(data);
    } catch {
      // ignore
    }
  }, []);

  useEffect(() => {
    if (showRotation && !rotationData) {
      loadRotation();
    }
  }, [showRotation, rotationData, loadRotation]);

  // Compute factor scores for heat score visualization
  const factorScoresMap = useMemo(() => {
    if (!sectors.length) return new Map<string, [number, number, number, number]>();
    const pctScores = normalizeValues(sectors.map(s => s.realtime_pct_change ?? s.pct_change));
    const capScores = normalizeValues(sectors.map(s => s.capital_inflow));
    const limScores = normalizeValues(sectors.map(s => s.realtime_limit_up_count ?? s.limit_up_count));
    const conScores = normalizeValues(sectors.map(s => s.days_continuous));
    const map = new Map<string, [number, number, number, number]>();
    sectors.forEach((s, i) => {
      map.set(s.sector_code, [pctScores[i], capScores[i], limScores[i], conScores[i]]);
    });
    return map;
  }, [sectors]);

  // Stage filter counts
  const stageCounts = useMemo(() => {
    const counts = { all: sectors.length, early: 0, mid: 0, late_end: 0 };
    sectors.forEach(s => {
      if (s.stage === "early") counts.early++;
      else if (s.stage === "mid") counts.mid++;
      else if (s.stage === "late" || s.stage === "end") counts.late_end++;
    });
    return counts;
  }, [sectors]);

  const filteredSectors = useMemo(() => {
    if (stageFilter === "all") return sectors;
    if (stageFilter === "late_end") return sectors.filter(s => s.stage === "late" || s.stage === "end");
    return sectors.filter(s => s.stage === stageFilter);
  }, [sectors, stageFilter]);

  const sectorBuckets = useMemo(() => {
    const mainline = sectors.slice(0, 3);
    const secondary = sectors.slice(3, 8);
    const watchlist = sectors.filter((sector) => ["late", "end"].includes(sector.stage ?? "")).slice(0, 4);
    return { mainline, secondary, watchlist };
  }, [sectors]);

  return (
    <ErrorBoundary>
    <div className="max-w-7xl mx-auto px-4 md:px-8 pt-6 pb-20 md:pb-10">
      <div className="animate-fade-in-up mb-5">
        <h1 className="text-lg font-bold tracking-tight">板块主线</h1>
        <p className="text-xs text-text-muted mt-0.5">
          判断当前主线、板块阶段、资金持续性和领涨股强度
          {hasRealtime && <span className="text-emerald-400/60 ml-1">· 今日实时优先</span>}
        </p>
        {hasRealtime && dataMode === "realtime_today" && (
          <p className="text-[11px] text-text-muted/70 mt-2">
            当前使用东方财富今日板块榜，涨幅、成交额、上涨/下跌家数与领涨股均为今日实时/收盘快照。
          </p>
        )}
        {hasRealtime && dataMode === "realtime_overlay" && (
          <p className="text-[11px] text-text-muted/70 mt-2">
            盘中模式下，涨幅、成交额、上涨/下跌家数与领涨股为实时覆盖；阶段、资金连续性等结构字段仍基于
            <span className="text-text-secondary"> {structureTradeDate || "最近交易日"} </span>
            的板块快照。
          </p>
        )}
      </div>

      {!sectors.length ? (
        <div className="glass-card-static p-12 text-center animate-fade-in-up">
          <div className="text-text-muted text-sm mb-1">暂无板块数据</div>
          <div className="text-text-muted/50 text-xs">触发扫描后自动更新</div>
        </div>
      ) : (
        <div className="grid grid-cols-1 xl:grid-cols-[minmax(0,1.35fr)_340px] gap-5">
          <section className="space-y-4">
            <MainlineCommandDeck
              mainline={sectorBuckets.mainline}
              secondary={sectorBuckets.secondary}
              watchlist={sectorBuckets.watchlist}
            />

            <div className="glass-card-static p-4 animate-fade-in-up">
              <div className="flex flex-wrap items-center justify-between gap-3 mb-3">
                <div>
                  <div className="text-[10px] uppercase tracking-[0.22em] text-text-muted font-semibold">板块列表</div>
                  <div className="text-sm text-text-secondary mt-1">先按阶段筛，再看每个板块的资金、阶段和领涨股结构。</div>
                </div>
                <div className="flex flex-wrap items-center gap-2">
                  {[
                    { key: "all", label: "全部", count: stageCounts.all },
                    { key: "early", label: "启动期", count: stageCounts.early },
                    { key: "mid", label: "发展期", count: stageCounts.mid },
                    { key: "late_end", label: "后期/尾声", count: stageCounts.late_end },
                  ].map(tab => (
                    <button
                      key={tab.key}
                      onClick={() => setStageFilter(tab.key)}
                      className={`text-xs px-3 py-1.5 rounded-lg font-medium transition-all ${
                        stageFilter === tab.key
                          ? "bg-gradient-to-r from-amber-500/20 to-amber-600/15 text-amber-400 border border-amber-500/15"
                          : "bg-surface-2 text-text-muted hover:text-text-secondary border border-transparent"
                      }`}
                    >
                      {tab.label}
                      <span className="ml-1 text-[10px] text-text-muted/50">{tab.count}</span>
                    </button>
                  ))}
                </div>
              </div>

              {!filteredSectors.length ? (
                <div className="rounded-2xl border border-border-subtle bg-surface-1/70 p-8 text-center text-sm text-text-muted">
                  当前筛选下无板块数据
                </div>
              ) : (
                <div className="grid grid-cols-1 md:grid-cols-2 gap-4 max-h-[1200px] overflow-y-auto pr-1">
                  {filteredSectors.map((sector) => {
                    const originalIndex = sectors.findIndex(s => s.sector_code === sector.sector_code);
                    return (
                      <SectorDetailCard
                        key={sector.sector_code}
                        sector={sector}
                        index={originalIndex}
                        factorScores={factorScoresMap.get(sector.sector_code)}
                      />
                    );
                  })}
                </div>
              )}
            </div>
          </section>

          <aside className="space-y-4">
            <FocusSummary sectors={sectors} />
            <div className="glass-card-static p-4 animate-fade-in-up">
              <div className="flex items-center justify-between gap-3">
                <div>
                  <div className="text-[10px] uppercase tracking-[0.22em] text-cyan-400 font-semibold">轮动观察</div>
                  <div className="text-sm text-text-secondary mt-1">轮动图收纳在侧栏，避免首屏被大图挤占。</div>
                </div>
                <button
                  onClick={() => setShowRotation(!showRotation)}
                  className={`text-xs px-3 py-2 rounded-xl font-medium transition-all ${
                    showRotation
                      ? "bg-gradient-to-r from-amber-500/25 to-amber-600/20 text-amber-400 border border-amber-500/15"
                      : "bg-surface-2 text-text-muted hover:text-text-secondary border border-transparent"
                  }`}
                >
                  {showRotation ? "收起" : "展开"}
                </button>
              </div>
            </div>

            {showRotation ? (
              rotationData && rotationData.sectors.length > 0 ? (
                <SectorRotationChart data={rotationData} />
              ) : (
                <div className="glass-card-static p-8 text-center">
                  <div className="w-6 h-6 border-2 border-amber-400/30 border-t-amber-400 rounded-full animate-spin mx-auto mb-2" />
                  <div className="text-xs text-text-muted">加载轮动数据...</div>
                </div>
              )
            ) : null}
          </aside>
        </div>
      )}
    </div>
    </ErrorBoundary>
  );
}

function MainlineCommandDeck({
  mainline,
  secondary,
  watchlist,
}: {
  mainline: SectorData[];
  secondary: SectorData[];
  watchlist: SectorData[];
}) {
  return (
    <div className="glass-card-static p-5 animate-fade-in-up mb-4 overflow-hidden relative">
      <div className="absolute right-[-120px] top-[-120px] w-72 h-72 rounded-full bg-amber-500/[0.045] blur-3xl pointer-events-none" />
      <div className="relative">
        <div className="text-[10px] uppercase tracking-[0.22em] text-amber-400 font-semibold mb-2">Sector Command</div>
        <h2 className="text-xl font-bold tracking-tight">主线不是排行榜，是今天的方向分层</h2>
        <p className="text-sm text-text-secondary leading-relaxed mt-2">
          主线决定是否值得参与，次主线决定是否做轮动，观察线只保留跟踪，不抢跑。
        </p>
        <div className="grid grid-cols-1 xl:grid-cols-3 gap-3 mt-4">
          <SectorLane title="今日主线" description="可以围绕龙头和回流机会制定计划" tone="red" sectors={mainline} />
          <SectorLane title="次主线" description="可跟踪轮动，不宜当主仓位方向" tone="amber" sectors={secondary} />
          <SectorLane title="观察线" description="只看变化，不在当前阶段主动追击" tone="slate" sectors={watchlist} />
        </div>
      </div>
    </div>
  );
}

function SectorLane({
  title,
  description,
  tone,
  sectors,
}: {
  title: string;
  description: string;
  tone: "red" | "amber" | "slate";
  sectors: SectorData[];
}) {
  const toneClass = tone === "red"
    ? "border-red-500/15 bg-red-500/[0.04] text-red-400"
    : tone === "amber"
    ? "border-amber-500/15 bg-amber-500/[0.04] text-amber-400"
    : "border-border-subtle bg-surface-1 text-text-secondary";

  return (
    <div className="rounded-2xl bg-surface-1/70 border border-border-subtle p-4">
      <div className="flex items-center justify-between gap-3 mb-2">
        <div>
          <h3 className="text-sm font-bold tracking-tight">{title}</h3>
          <p className="text-[11px] text-text-muted mt-0.5">{description}</p>
        </div>
        <span className={`text-xs font-mono tabular-nums rounded-lg border px-2 py-1 ${toneClass}`}>
          {sectors.length}
        </span>
      </div>
      {sectors.length ? (
        <div className="space-y-2.5 mt-3">
          {sectors.map((sector) => (
            <SectorLaneRow key={sector.sector_code} sector={sector} />
          ))}
        </div>
      ) : (
        <div className="text-xs text-text-muted mt-3">暂无数据</div>
      )}
    </div>
  );
}

function SectorLaneRow({ sector }: { sector: SectorData }) {
  const stage = getStageInfo(sector.stage ?? "");
  const leaders = sector.is_realtime
    ? (sector.leading_stocks_realtime?.length ? sector.leading_stocks_realtime : sector.leading_stocks)
    : sector.leading_stocks;
  const leadText = leaders?.slice(0, 2).map((stock) => stock.name).join(" / ") || "暂无代表股";
  const action = getSectorAction(sector);
  const displayPct = sector.realtime_pct_change ?? sector.pct_change;

  return (
    <div className="rounded-xl bg-surface-2/70 border border-border-subtle px-3 py-2.5">
      <div className="flex items-center justify-between gap-2">
        <div className="min-w-0">
          <div className="flex items-center gap-2">
            <span className="text-sm font-semibold truncate">{sector.sector_name}</span>
            <span className={`text-[10px] px-1.5 py-0.5 rounded-md border ${stage.bg} ${stage.color}`}>
              {stage.label}
            </span>
          </div>
          <div className="text-[11px] text-text-muted mt-0.5 line-clamp-1">
            代表股：{leadText}
          </div>
        </div>
        <div className="text-right shrink-0">
          <div className={`text-sm font-bold font-mono tabular-nums ${displayPct >= 0 ? "text-red-400" : "text-emerald-400"}`}>
            {displayPct > 0 ? "+" : ""}{displayPct.toFixed(2)}%
          </div>
          <div className="text-[10px] text-text-muted">{action.label}</div>
        </div>
      </div>
      <div className="grid grid-cols-2 gap-2 mt-2 text-[11px]">
        <div className="rounded-lg bg-surface-1 px-2 py-1.5 text-text-secondary">
          参与建议：{action.advice}
        </div>
        <div className="rounded-lg bg-surface-1 px-2 py-1.5 text-text-secondary">
          失效观察：{action.risk}
        </div>
      </div>
    </div>
  );
}

function getSectorAction(sector: SectorData) {
  const stage = sector.stage ?? "";
  const mainForce = sector.main_force_ratio ?? 0;
  const pct = sector.realtime_pct_change ?? sector.pct_change;

  if (stage === "early") {
    return {
      label: "可进攻",
      advice: "盯龙头和首个分歧回流，优先轻仓试错。",
      risk: "若涨停家数不扩散或龙头走弱，立刻降级观察。",
    };
  }
  if (stage === "mid" && mainForce > 20 && pct > 0) {
    return {
      label: "回流参与",
      advice: "等分歧后的承接确认，不追情绪顶点。",
      risk: "若主力占比回落或板块跟风掉队，停止追击。",
    };
  }
  return {
    label: "只观察",
    advice: "只保留跟踪，不作为当前主仓位方向。",
    risk: "若主线切换或板块退潮，及时移出观察列表。",
  };
}

function SectorRotationChart({ data }: { data: SectorRotationData }) {
  const [el, setEl] = useState<HTMLDivElement | null>(null);
  const { theme } = useNextTheme();

  useEffect(() => {
    if (!el || !data.sectors.length) return;

    let chart: ReturnType<typeof import("echarts")["init"]> | null = null;

    import("echarts").then((ec) => {
      if (!el) return;
      const isDark = theme !== "light";
      chart = ec.init(el, isDark ? "dark" : undefined);

      const isLight = theme === "light";
      const axisLabelColor = isLight ? "#6b7280" : "#94a3b8";
      const dates = data.dates.map((d) => d.slice(4));
      const sectorNames = data.sectors.map((s) => s.sector_name);

      const heatData: [number, number, number][] = [];
      let minVal = Infinity;
      let maxVal = -Infinity;
      data.sectors.forEach((sector, yi) => {
        dates.forEach((_, xi) => {
          const dayData = sector.daily_data.find((d) => data.dates[xi] && d.trade_date === data.dates[xi]);
          const val = dayData?.pct_change ?? 0;
          heatData.push([xi, yi, val]);
          if (val < minVal) minVal = val;
          if (val > maxVal) maxVal = val;
        });
      });

      chart.setOption({
        backgroundColor: "transparent",
        tooltip: {
          formatter: (params: { data: number[] }) => {
            const [x, y, val] = params.data;
            return `${sectorNames[y]}<br/>${dates[x]}: <b>${val > 0 ? "+" : ""}${val.toFixed(2)}%</b>`;
          },
        },
        grid: { left: "15%", right: "5%", top: "5%", bottom: "12%" },
        xAxis: {
          type: "category",
          data: dates,
          splitArea: { show: true },
          axisLabel: { fontSize: 10, color: axisLabelColor },
        },
        yAxis: {
          type: "category",
          data: sectorNames,
          axisLabel: { fontSize: 10, color: axisLabelColor, width: 60, overflow: "truncate" },
        },
        visualMap: {
          min: minVal,
          max: maxVal,
          calculable: true,
          orient: "horizontal",
          left: "center",
          bottom: 0,
          inRange: {
            color: ["#22c55e", "#fbbf24", "#ef4444"],
          },
          textStyle: { fontSize: 10, color: axisLabelColor },
        },
        series: [{
          type: "heatmap",
          data: heatData,
          label: {
            show: true,
            fontSize: 9,
            formatter: (params: { data: number[] }) => {
              const val = params.data[2];
              return val > 0 ? `+${val.toFixed(1)}` : val.toFixed(1);
            },
          },
        }],
      });

      const handleResize = () => chart?.resize();
      window.addEventListener("resize", handleResize);
    });

    return () => { chart?.dispose(); };
  }, [data, theme, el]);

  return (
    <div className="glass-card-static p-4">
      <h2 className="text-xs font-semibold text-text-muted uppercase tracking-wider mb-3">
        近{data.dates.length}日板块轮动
      </h2>
      <div ref={setEl} className="w-full" style={{ height: Math.max(data.sectors.length * 28 + 60, 200) }} />
    </div>
  );
}

function useNextTheme() {
  // eslint-disable-next-line @typescript-eslint/no-require-imports
  const { useTheme } = require("next-themes");
  return useTheme();
}
