import { useCallback, useState } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Link } from "react-router-dom";
import CompassArt from "../components/CompassArt";
import EraDetailPanel from "../components/EraDetailPanel";
import { api, ApiError, type MacroPayload, type WeathervanePayload, type CalendarPayload } from "../lib/api";
import { Card, Loading, ErrorState, MissingKey, Explain, Tag } from "../components/ui";
import { setFreshQueryData } from "../lib/refresh";
import { ScoreRing, RangeBar } from "../components/Gauges";
import { prepareCalendarEvents } from "../lib/calendarInfo";
import CalendarWeekPreview from "../components/CalendarWeekPreview";
import { PERCENTILE_METHOD, WEATHERVANE_METHOD } from "../lib/explainers";
import {
  scoreBand,
  interpretIndicator,
  signalTagTone,
  buildMacroExplainRows,
  indicatorExplainRows,
  signalHint,
} from "../lib/interpret";
import { AppIcon, WeatherBandIcon, type IconName } from "../components/PixelIcons";
import SocialWatchPanel from "../components/SocialWatchPanel";

const MAP_TILES: { to: string; icon: IconName; t: string; d: string }[] = [
  { to: "/market", icon: "world", t: "市場世界", d: "總經氣候・大資金・事件日曆" },
  { to: "/research", icon: "sword", t: "個股背包", d: "分群追蹤・K線・財報・籌碼" },
  { to: "/skills", icon: "scroll", t: "心法技能樹", d: "110 條心法・8 大主題群・心法卡" },
  { to: "/patterns", icon: "cards", t: "線型圖鑑", d: "收集技術招式" },
  { to: "/journal", icon: "folder", t: "復盤戰績", d: "交易紀錄・AI 交易員・倉位簿" },
  { to: "/profile", icon: "wizard", t: "角色養成", d: "EXP・徽章・五維・學習路線" },
];

function weatherClass(score: number) {
  return score >= 60 ? "weather fair" : score < 40 ? "weather storm" : "weather";
}

export default function Home() {
  const queryClient = useQueryClient();
  const macroQ = useQuery({ queryKey: ["macro"], queryFn: () => api.macro() });
  const wvQ = useQuery({ queryKey: ["weathervane", "10y"], queryFn: () => api.weathervane("10y") });
  const wlQ = useQuery({ queryKey: ["watchlist"], queryFn: api.watchlist, staleTime: 60_000 });
  const wlKey = (wlQ.data?.groups || []).flatMap((g) => g.symbols || []).join(",");
  const calQ = useQuery({
    queryKey: ["calendar", wlKey],
    queryFn: () => api.calendar(),
    enabled: !wlQ.isLoading,
  });
  const [macroRefreshing, setMacroRefreshing] = useState(false);
  const [wvRefreshing, setWvRefreshing] = useState(false);
  const [calRefreshing, setCalRefreshing] = useState(false);

  const refreshMacro = useCallback(async () => {
    setMacroRefreshing(true);
    try {
      await setFreshQueryData(queryClient, ["macro"], () => api.macro(true));
    } finally {
      setMacroRefreshing(false);
    }
  }, [queryClient]);

  const refreshWeathervane = useCallback(async () => {
    setWvRefreshing(true);
    try {
      await setFreshQueryData(queryClient, ["weathervane", "10y"], () => api.weathervane("10y"));
    } finally {
      setWvRefreshing(false);
    }
  }, [queryClient]);

  const refreshCalendar = useCallback(async () => {
    setCalRefreshing(true);
    try {
      await setFreshQueryData(queryClient, ["calendar", wlKey], () => api.calendar(undefined, undefined, true));
    } finally {
      setCalRefreshing(false);
    }
  }, [queryClient, wlKey]);

  const missingKey =
    macroQ.error instanceof ApiError && macroQ.error.code === "missing_api_key" ? macroQ.error : null;

  return (
    <>
      <div className="page-head">
        <div className="eyebrow">每日 5 分鐘主線</div>
        <h1 className="page-title-row">
          <AppIcon name="castle" size={38} framed glow variant="hero" />
          冒險者基地
        </h1>
        <p>每個數字都會告訴你：現在偏高還偏低、對投資順風還逆風，以及分數怎麼來的。</p>
      </div>

      {missingKey && <MissingKey message={missingKey.message} hint={missingKey.body?.hint} />}

      <div className="grid g2">
        <Card
          title="今日天氣 · 總經健康"
          ico={<AppIcon name="thermometer" size={24} framed variant="hero" />}
          ai
          aiFocus={{ cardTitle: "今日天氣 · 總經健康", tab: "weather" }}
          onRefresh={() => void refreshMacro()}
          refreshing={macroRefreshing}
        >
          <WeatherBlock q={macroQ} />
        </Card>

        <Card
          title={
            <>
              編年史羅盤 · 現在像哪段歷史
              <Explain label={WEATHERVANE_METHOD.label} rows={WEATHERVANE_METHOD.rows} align="right" />
            </>
          }
          ico={<AppIcon name="compass" size={24} framed variant="hero" />}
          ai
          aiFocus={{ cardTitle: "編年史羅盤", label: "歷史相似期", tab: "compass" }}
          onRefresh={() => void refreshWeathervane()}
          refreshing={wvRefreshing}
        >
          <CompassBlock q={wvQ} />
        </Card>
      </div>

      <SocialWatchPanel className="mt" limit={8} />

      <div className="grid g2 mt">
        <Card
          title={
            <>
              關鍵指標 · 歷史定位
              <Explain label={PERCENTILE_METHOD.label} rows={PERCENTILE_METHOD.rows} align="right" />
            </>
          }
          ico={<AppIcon name="chart" size={24} framed variant="hero" />}
          onRefresh={() => void refreshWeathervane()}
          refreshing={wvRefreshing}
        >
          <IndicatorBars q={wvQ} />
        </Card>

        <Card
          title="本週重要日期 · 世界事件"
          ico={<AppIcon name="calendar" size={24} framed variant="hero" />}
          onRefresh={() => void refreshCalendar()}
          refreshing={calRefreshing}
        >
          <CalendarBlock q={calQ} />
        </Card>
      </div>

      <h3 className="pixel mt page-section-title" style={{ marginBottom: 12 }}>
        <AppIcon name="map" size={26} framed variant="hero" />
        前往各區域
      </h3>
      <div className="grid g3 map-grid">
        {MAP_TILES.map((m) => (
          <Link key={m.to} to={m.to} className="map-tile">
            <span className="ic">
              <AppIcon name={m.icon} size={36} framed glow variant="hero" />
            </span>
            <span className="t">{m.t}</span>
            <span className="d">{m.d}</span>
          </Link>
        ))}
      </div>

      <div className="disclaimer">本工具僅供學習觀測，所有內容不構成投資建議</div>
    </>
  );
}

function WeatherBlock({ q }: { q: { data?: MacroPayload; isLoading: boolean; error: unknown } }) {
  if (q.isLoading) return <Loading />;
  if (q.error instanceof ApiError && q.error.code === "missing_api_key")
    return <p className="muted small">設定金鑰後即可顯示總經健康分數。</p>;
  if (q.error || !q.data) return <ErrorState detail={(q.error as Error)?.message} />;
  const m = q.data;
  const score = m.score ?? 0;
  const band = scoreBand(score);
  const regime = m.regime?.label || band.label;
  const breakdown = (m.breakdown || []) as { label: string; delta: number; note: string }[];
  const signals = (m.signals || []) as { label?: string; value?: string; colorKey?: string }[];
  const detailRows = buildMacroExplainRows(score, band, breakdown, signals);
  const methodRows = [
    { dt: "主燈號", dd: `${score} 分（趨勢總經分）${m.scoreChange != null ? `，較前一日 ${m.scoreChange >= 0 ? "+" : ""}${m.scoreChange}` : ""}` },
    { dt: "原始即時分", dd: `${m.rawScore ?? score} 分；反映最新資料與市場壓力，但不直接拿來每日換燈。` },
    { dt: "資料覆蓋", dd: m.coverage ? `${m.coverage.available}/${m.coverage.expected} 項核心指標（${m.coverage.pct}%）` : "—" },
    { dt: "穩定方法", dd: m.scoreMethod?.description || "使用趨勢分降低日頻噪音。" },
  ];

  return (
    <div className={weatherClass(score)}>
      <ScoreRing score={score} />
      <div className="weather-body">
        <div className="weather-head">
          <div>
            <div className="weather-scoreline">
              <span className="weather-score-num">{score}</span>
              <span className="weather-score-unit">分</span>
              <Tag tone={band.tone}>{band.weather}</Tag>
            </div>
            <div className="weather-regime">
              <WeatherBandIcon kind={band.weatherIcon} size={18} />
              {regime}
            </div>
            <div className="small muted">
              即時 {m.rawScore ?? score} · 覆蓋 {m.coverage?.available ?? "—"}/{m.coverage?.expected ?? "—"}
            </div>
          </div>
          <Explain label="總經健康分詳解" rows={[...methodRows, ...detailRows]} align="right" wide />
        </div>
        <p className="weather-summary">{band.meaning}</p>
        {signals.length > 0 && (
          <div className="weather-pills">
            {signals.map((s, i) => (
              <Explain
                key={s.label || i}
                align="left"
                rows={[
                  {
                    dt: s.label || "訊號",
                    dd: signalHint(s.label, s.value) || `目前狀態：${s.value || "—"}`,
                  },
                ]}
                trigger={
                  <span className={"weather-pill " + signalTagTone(s.colorKey)}>
                    <span className="weather-pill-k">{s.label}</span>
                    <span className="weather-pill-v">{s.value || "—"}</span>
                  </span>
                }
              />
            ))}
          </div>
        )}
        {m.stale && <div className="small muted mt-s">（快取資料）</div>}
      </div>
    </div>
  );
}

function CompassBlock({ q }: { q: { data?: WeathervanePayload; isLoading: boolean; error: unknown } }) {
  const [eraOpen, setEraOpen] = useState(false);
  if (q.isLoading) return <Loading />;
  if (q.error || !q.data) return <ErrorState detail={(q.error as Error)?.message} />;
  const wv = q.data;
  if (wv.error || !wv.similar)
    return <p className="muted small">{wv.error ? "風向標暫無資料（可能尚未累積足夠歷史）。" : "歷史比對資料不足。"}</p>;
  const sim = wv.similar;
  return (
    <>
      <button type="button" className="era-card era-card-compact" onClick={() => setEraOpen(true)}>
        <CompassArt className="compass-art-sm" />
        <div className="era-card-body">
          <div className="era">最像 {sim.regimeLabel ? `${sim.date}（${sim.regimeLabel}）` : sim.date}</div>
          <p className="era-card-teaser small">
            {sim.detail?.whySimilar || "點開查看指標對照、當時股市與大事件。"}
          </p>
          <span className="era-card-cta">開啟編年史檔案 →</span>
        </div>
      </button>
      <EraDetailPanel similar={sim} open={eraOpen} onClose={() => setEraOpen(false)} />
      <Link to="/market" className="small muted" style={{ display: "inline-block", marginTop: 8 }}>
        前往市場世界 · 編年史羅盤
      </Link>
    </>
  );
}

function IndicatorBars({ q }: { q: { data?: WeathervanePayload; isLoading: boolean; error: unknown } }) {
  if (q.isLoading) return <Loading />;
  if (q.error || !q.data) return <ErrorState detail={(q.error as Error)?.message} />;
  const items = (q.data.indicators || []).slice(0, 5);
  if (!items.length) return <p className="muted small">尚無指標歷史可定位。</p>;
  return (
    <div>
      {items.map((it) => {
        const interp = interpretIndicator(it);
        return (
          <div className="indicator-block" key={it.key}>
            <div className="indicator-head">
              <span className="k" style={{ display: "flex", alignItems: "center", gap: 6 }}>
                {it.label}
                <Explain tip={it.tip} />
              </span>
              <span className="rangebar-val">
                {it.valueText ?? (it.value != null ? it.value : "—")}
              </span>
            </div>
            <div className="indicator-meta">
              <Explain
                align="left"
                rows={indicatorExplainRows(it.label, interp, interp.verdict)}
                trigger={
                  <span className={"indicator-pill " + interp.tone}>
                    近 10 年{interp.level} · {interp.stance}
                    {it.pct != null && <span className="indicator-pct">　{Math.round(it.pct)}%</span>}
                  </span>
                }
              />
            </div>
            <RangeBar pct={it.pct} />
          </div>
        );
      })}
    </div>
  );
}

function CalendarBlock({ q }: { q: { data?: CalendarPayload; isLoading: boolean; error: unknown } }) {
  if (q.isLoading) return <Loading />;
  if (q.error || !q.data) return <ErrorState detail={(q.error as Error)?.message} />;
  const today = new Date().toISOString().slice(0, 10);
  const in7 = new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 10);
  const events = prepareCalendarEvents(q.data.events || [], q.data.portfolioSymbols || []).filter(
    (e) => e.date >= today && e.date <= in7,
  );
  return (
    <div>
      <div className="small muted" style={{ marginBottom: 12 }}>
        週曆檢視：總經大事與<b>背包內個股財報</b>（自動去重）。點日期看完整說明與 ? 解讀。
      </div>
      <CalendarWeekPreview events={events} />
    </div>
  );
}
