import { useCallback, useMemo, useState, type ReactNode } from "react";
import { Link } from "react-router-dom";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { api, ApiError, type MacroPayload, type WeathervanePayload } from "../lib/api";
import { Card, Tag, Loading, ErrorState, MissingKey, Explain, StatCard, formatTipContext, RefreshButton } from "../components/ui";
import { setFreshQueryData } from "../lib/refresh";
import { RangeBar } from "../components/Gauges";
import SeriesChart from "../components/SeriesChart";
import YieldCurve from "../components/YieldCurve";
import CompassArt from "../components/CompassArt";
import EraDetailPanel from "../components/EraDetailPanel";
import { AppIcon, GroupIcon } from "../components/PixelIcons";
import { prepareCalendarEvents } from "../lib/calendarInfo";
import CalendarBoard from "../components/CalendarBoard";
import { WEATHERVANE_METHOD } from "../lib/explainers";
import { signalTagTone, signalHint } from "../lib/interpret";
import { RangeChips, SERIES_RANGES, WV_WINDOWS, wvWindowHint, type SeriesRange, type WvWindow } from "../components/RangeChips";
import SocialWatchPanel from "../components/SocialWatchPanel";

type TabKey = "macro" | "compass" | "flow" | "calendar";
const TABS: { key: TabKey; label: string; icon: ReactNode }[] = [
  { key: "macro", label: "總經氣候", icon: <AppIcon name="macro" size={22} framed variant="nav" /> },
  { key: "compass", label: "編年史羅盤", icon: <AppIcon name="compass" size={22} framed variant="nav" /> },
  { key: "flow", label: "戰場情報", icon: <AppIcon name="flow" size={22} framed variant="nav" /> },
  { key: "calendar", label: "事件日曆", icon: <AppIcon name="calendar" size={22} framed variant="nav" /> },
];

const FOCUS_KEYS = [
  { key: "fed_funds", label: "聯邦基金利率" },
  { key: "treasury_10y", label: "10Y 殖利率" },
  { key: "cpi", label: "CPI 年增" },
  { key: "unemployment", label: "失業率" },
  { key: "vix", label: "VIX" },
  { key: "sp500", label: "S&P 500" },
];

export default function Market() {
  const [tab, setTab] = useState<TabKey>("macro");
  const queryClient = useQueryClient();
  const macroQ = useQuery({ queryKey: ["macro"], queryFn: () => api.macro() });
  const [macroRefreshing, setMacroRefreshing] = useState(false);

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

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

  return (
    <>
      <div className="page-head">
        <div className="eyebrow">深度觀測</div>
        <h1 className="page-title-row">
          <AppIcon name="world" size={38} framed glow variant="hero" className="page-ico" />
          市場世界 · 氣候
        </h1>
        <p>總經氣候、現在像哪段歷史、大資金往哪流、未來有哪些世界事件。</p>
      </div>

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

      <div className="tabs">
        {TABS.map((t) => (
          <div key={t.key} className={"tab tab-ico" + (tab === t.key ? " active" : "")} onClick={() => setTab(t.key)}>
            <span className="tab-icon">{t.icon}</span>
            {t.label}
          </div>
        ))}
      </div>

      {tab === "macro" && <MacroTab q={macroQ} onRefreshMacro={() => void refreshMacro()} macroRefreshing={macroRefreshing} />}
      {tab === "compass" && <CompassTab />}
      {tab === "flow" && <FlowTab />}
      {tab === "calendar" && <CalendarTab />}

      <div className="disclaimer">資料來源：FRED／Yahoo Finance，僅供學習，不構成投資建議</div>
    </>
  );
}

function MacroTab({
  q,
  onRefreshMacro,
  macroRefreshing,
}: {
  q: { data?: MacroPayload; isLoading: boolean; error: unknown };
  onRefreshMacro: () => void;
  macroRefreshing?: boolean;
}) {
  const queryClient = useQueryClient();
  const [focus, setFocus] = useState("treasury_10y");
  const [seriesRange, setSeriesRange] = useState<SeriesRange>("10y");
  const [seriesRefreshing, setSeriesRefreshing] = useState(false);
  const seriesQ = useQuery({
    queryKey: ["series", focus, seriesRange],
    queryFn: () => api.series(focus, seriesRange),
  });

  const refreshSeries = useCallback(async () => {
    setSeriesRefreshing(true);
    try {
      await setFreshQueryData(queryClient, ["series", focus, seriesRange], () => api.series(focus, seriesRange));
    } finally {
      setSeriesRefreshing(false);
    }
  }, [queryClient, focus, seriesRange]);

  if (q.isLoading) return <Loading />;
  if (q.error instanceof ApiError && q.error.code === "missing_api_key")
    return <p className="muted">設定 FRED 金鑰後即可顯示總經儀表板。</p>;
  if (q.error || !q.data) return <ErrorState detail={(q.error as Error)?.message} />;
  const m = q.data;

  return (
    <>
      <Card
        title="指標走勢"
        ico={<AppIcon name="chart" size={24} framed variant="hero" />}
        ai
        aiFocus={{ cardTitle: "指標走勢", label: focus, key: focus, tab: "macro" }}
        className="mt-s"
        onRefresh={() => void refreshSeries()}
        refreshing={seriesRefreshing}
      >
        <div className="tabs" style={{ borderBottom: "none", marginBottom: 10 }}>
          {FOCUS_KEYS.map((f) => (
            <div key={f.key} className={"tab" + (focus === f.key ? " active" : "")} onClick={() => setFocus(f.key)}>
              {f.label}
            </div>
          ))}
        </div>
        <RangeChips
          options={[...SERIES_RANGES]}
          value={seriesRange}
          onChange={setSeriesRange}
          hint={seriesRange === "max" ? "最遠＝資料庫內該指標全部歷史（各指標起點不同）" : undefined}
        />
        {seriesQ.isLoading ? (
          <Loading />
        ) : seriesQ.error || !seriesQ.data ? (
          <ErrorState detail={(seriesQ.error as Error)?.message} />
        ) : seriesQ.data.points.length ? (
          <>
            <div className="chart-panel">
              <SeriesChart data={seriesQ.data.points} />
            </div>
            <div className="chart-span small muted">
              {seriesQ.data.points[0].date} ～ {seriesQ.data.points[seriesQ.data.points.length - 1].date}
              （{seriesQ.data.points.length} 筆・{seriesRange === "max" ? "最遠" : seriesRange}）
            </div>
          </>
        ) : (
          <p className="muted small">此指標尚無歷史序列（可能後端尚未累積）。</p>
        )}
      </Card>

      <div className="grid g2 mt">
        <Card
          title="殖利率曲線"
          ico={<AppIcon name="rates" size={24} framed variant="hero" />}
          onRefresh={onRefreshMacro}
          refreshing={macroRefreshing}
        >
          <YieldCurve yc={m.yieldCurve} />
        </Card>
        <Card
          title="本日訊號"
          ico={<AppIcon name="sentiment" size={24} framed variant="hero" />}
          onRefresh={onRefreshMacro}
          refreshing={macroRefreshing}
        >
          {(m.signals || []).length ? (
            <div className="dl">
              {(m.signals as { label?: string; value?: string; colorKey?: string; text?: string }[])
                .slice(0, 6)
                .map((s, i) => (
                  <div className="row" key={s.label || i} style={{ alignItems: "center" }}>
                    <span className="k" style={{ display: "flex", alignItems: "center", gap: 6 }}>
                      {s.label || s.text}
                      {signalHint(s.label, s.value) && (
                        <Explain rows={[{ dt: s.label || "訊號", dd: signalHint(s.label, s.value)! }]} align="left" />
                      )}
                    </span>
                    <span className="v">
                      <Tag tone={signalTagTone(s.colorKey)}>{s.value || "—"}</Tag>
                    </span>
                  </div>
                ))}
            </div>
          ) : (
            <p className="muted small">今日無特別訊號。</p>
          )}
        </Card>
      </div>

      {(m.groups || []).length ? (
        <div className="macro-groups-toolbar mt">
          <RefreshButton onClick={onRefreshMacro} loading={macroRefreshing} label="重新整理總經" />
        </div>
      ) : null}
      {(m.groups || []).map((g) => (
        <div key={g.key} className="mt">
          <h3 className="pixel group-title" style={{ marginBottom: 10 }}>
            <GroupIcon groupKey={g.key} size={22} />
            {g.title}
          </h3>
          <div className="grid g3">
            {g.cards.map((c) => (
              <StatCard
                key={c.key}
                label={c.label}
                labelEn={c.labelEn}
                value={c.value ?? "—"}
                change={c.change as any}
                dir={c.dir}
                sub={c.human ?? formatTipContext(c.context) ?? undefined}
                tip={c.tip}
              />
            ))}
          </div>
        </div>
      ))}
    </>
  );
}

function CompassTab() {
  const queryClient = useQueryClient();
  const [eraOpen, setEraOpen] = useState(false);
  const [wvWindow, setWvWindow] = useState<WvWindow>("max");
  const [wvRefreshing, setWvRefreshing] = useState(false);
  const wvQ = useQuery({
    queryKey: ["weathervane", wvWindow],
    queryFn: () => api.weathervane(wvWindow),
  });

  const refreshWeathervane = useCallback(async () => {
    setWvRefreshing(true);
    try {
      await setFreshQueryData(queryClient, ["weathervane", wvWindow], () => api.weathervane(wvWindow));
    } finally {
      setWvRefreshing(false);
    }
  }, [queryClient, wvWindow]);
  if (wvQ.isLoading) return <Loading />;
  if (wvQ.error || !wvQ.data) return <ErrorState detail={(wvQ.error as Error)?.message} />;
  const wv: WeathervanePayload = wvQ.data;
  const sim = wv.similar;
  const preview = sim?.detail;

  return (
    <>
      <Card
        title={
          <>
            現在最像哪段歷史
            <Explain label={WEATHERVANE_METHOD.label} rows={WEATHERVANE_METHOD.rows} align="right" />
          </>
        }
        ico={<AppIcon name="compass" size={24} framed variant="hero" />}
        className="mt-s"
        ai
        aiFocus={{ cardTitle: "現在最像哪段歷史", label: "編年史羅盤", tab: "compass" }}
        onRefresh={() => void refreshWeathervane()}
        refreshing={wvRefreshing}
      >
        <RangeChips
          options={[...WV_WINDOWS]}
          value={wvWindow}
          onChange={setWvWindow}
          hint={wvWindowHint(wvWindow)}
        />
        {sim ? (
          <>
            <button type="button" className="era-card" onClick={() => setEraOpen(true)}>
              <CompassArt />
              <div className="era-card-body">
                <div className="era">
                  {sim.regimeLabel ? `${sim.date}（${sim.regimeLabel}）` : sim.date}
                </div>
                <p className="era-card-teaser">
                  {preview?.whySimilar || sim.note || "點開查看指標對照、當時股市與大事件。"}
                </p>
                <div className="era-card-foot">
                  <Tag tone="gold">相似距離 {sim.distance?.toFixed(2)}</Tag>
                  {preview?.market?.trendLabel && (
                    <Tag tone={preview.market.ret12mAfter != null && preview.market.ret12mAfter >= 0 ? "up" : "down"}>
                      當時一年後 · {preview.market.trendLabel}
                    </Tag>
                  )}
                  <span className="era-card-cta">開啟編年史檔案 →</span>
                </div>
              </div>
            </button>
            <EraDetailPanel similar={sim} open={eraOpen} onClose={() => setEraOpen(false)} />
          </>
        ) : (
          <p className="muted small">{wv.error || "歷史比對資料不足（需累積較長序列）。"}</p>
        )}
      </Card>

      <SocialWatchPanel className="mt" />

      <Card
        title="全指標歷史定位"
        ico={<AppIcon name="chart" size={20} framed />}
        className="mt"
        onRefresh={() => void refreshWeathervane()}
        refreshing={wvRefreshing}
      >
        {(wv.indicators || []).length ? (
          <div className="grid g2">
            {wv.indicators.map((it) => (
              <div key={it.key} style={{ marginBottom: 8 }}>
                <div className="dl">
                  <div className="row" style={{ borderBottom: "none", padding: "2px 2px", alignItems: "center" }}>
                    <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 ?? "—"}
                      {it.pct != null && <span className="muted small">　{Math.round(it.pct)} 分位</span>}
                    </span>
                  </div>
                </div>
                <RangeBar pct={it.pct} />
              </div>
            ))}
          </div>
        ) : (
          <p className="muted small">尚無指標歷史可定位。</p>
        )}
      </Card>
    </>
  );
}

function FlowTab() {
  const queryClient = useQueryClient();
  const [secRefreshing, setSecRefreshing] = useState(false);
  const secQ = useQuery({ queryKey: ["sectors"], queryFn: () => api.sectors() });

  const refreshSectors = useCallback(async () => {
    setSecRefreshing(true);
    try {
      await setFreshQueryData(queryClient, ["sectors"], () => api.sectors(true));
    } finally {
      setSecRefreshing(false);
    }
  }, [queryClient]);
  if (secQ.isLoading) return <Loading label="抓取板塊資金（較慢）…" />;
  if (secQ.error || !secQ.data) return <ErrorState detail={(secQ.error as Error)?.message} />;
  const s = secQ.data;
  const sectors = (s.sectors || []).filter((x: any) => !x.error);
  const heat = [...sectors].sort((a: any, b: any) => (b.ret5d ?? -99) - (a.ret5d ?? -99));

  return (
    <>
      <Card
        title="板塊輪動 · 資金往哪流"
        ico={<AppIcon name="flow" size={24} framed variant="hero" />}
        className="mt-s"
        ai
        aiFocus={{ cardTitle: "板塊輪動", tab: "flow" }}
        onRefresh={() => void refreshSectors()}
        refreshing={secRefreshing}
      >
        {s.rotation && (
          <div className="editorial">
            目前狀態：<b>{s.rotation.regime}</b>。{s.rotation.regimeNote}
            <span className="by">— 戰場情報・依 SPDR 行業 ETF 相對強度</span>
          </div>
        )}
        <div className="grid g3 mt">
          {heat.map((r: any) => (
            <div className="card" key={r.etf}>
              <div className="dl">
                <div className="row" style={{ borderBottom: "none" }}>
                  <span className="k">
                    {r.nameZh} <span className="muted small">{r.etf}</span>
                  </span>
                  <span className="v">
                    <Tag tone={(r.ret5d ?? 0) >= 0 ? "up" : "down"}>
                      {r.ret5d != null ? `${r.ret5d >= 0 ? "+" : ""}${r.ret5d.toFixed(1)}% / 5日` : "—"}
                    </Tag>
                  </span>
                </div>
              </div>
              <div className="small muted mt-s">
                {r.quadrant?.labelZh ? `輪動：${r.quadrant.labelZh}` : ""}
                {r.rs20 != null ? `　RS20 ${r.rs20 >= 0 ? "+" : ""}${r.rs20.toFixed(1)}%` : ""}
              </div>
            </div>
          ))}
        </div>
      </Card>

      {s.institutional?.flowLeaders?.length > 0 && (
        <Card
          title="資金流向領先板塊"
          ico={<AppIcon name="chart" size={20} framed />}
          className="mt"
          onRefresh={() => void refreshSectors()}
          refreshing={secRefreshing}
        >
          <div className="dl">
            {s.institutional.flowLeaders.map((r: any) => (
              <div className="row" key={r.etf}>
                <span className="k">
                  {r.nameZh} <span className="muted small">{r.etf}</span>
                </span>
                <span className="v small">{r.note}</span>
              </div>
            ))}
          </div>
          {s.institutional.disclaimer && <div className="small muted mt-s">{s.institutional.disclaimer}</div>}
        </Card>
      )}
    </>
  );
}

function CalendarTab() {
  const queryClient = useQueryClient();
  const [calRefreshing, setCalRefreshing] = useState(false);
  const wlQ = useQuery({ queryKey: ["watchlist"], queryFn: api.watchlist, staleTime: 60_000 });
  const wlKey = useMemo(() => {
    const syms = (wlQ.data?.groups || []).flatMap((g) => g.symbols || []);
    return syms.join(",");
  }, [wlQ.data]);
  const calQ = useQuery({
    queryKey: ["calendar", wlKey],
    queryFn: () => api.calendar(),
    enabled: !wlQ.isLoading,
  });

  const refreshCalendar = useCallback(async () => {
    setCalRefreshing(true);
    try {
      await setFreshQueryData(queryClient, ["calendar", wlKey], () => api.calendar(undefined, undefined, true));
    } finally {
      setCalRefreshing(false);
    }
  }, [queryClient, wlKey]);
  if (calQ.isLoading || wlQ.isLoading) return <Loading />;
  if (calQ.error || !calQ.data) return <ErrorState detail={(calQ.error as Error)?.message} />;
  const portfolioSymbols = calQ.data.portfolioSymbols || [];
  const events = prepareCalendarEvents(calQ.data.events || [], portfolioSymbols);
  return (
    <Card
      title="未來世界事件 · BOSS 開放日"
      ico={<AppIcon name="calendar" size={24} framed variant="hero" />}
      className="mt-s"
      onRefresh={() => void refreshCalendar()}
      refreshing={calRefreshing}
    >
      <div className="small muted mt-s" style={{ marginBottom: 12 }}>
        行事曆格狀檢視：總經／Fed／四巫日 + <b>背包個股財報</b>（自動去重）。點日期格子，下方看完整說明與 ? 解讀。
      </div>
      <CalendarBoard
        events={events}
        portfolioCount={portfolioSymbols.length}
        start={calQ.data.start}
        end={calQ.data.end}
      />
    </Card>
  );
}
