"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { ErrorBoundary } from "@/components/error-boundary";
import { fetchAPI } from "@/lib/api";
import type { CatalystEvent, CatalystNewsItem, ThemeCatalystScore } from "@/lib/api";
import { useWebSocket } from "@/hooks/use-websocket";

type CatalystTone = "hot" | "warm" | "quiet";

export default function SentimentPage() {
  const [news, setNews] = useState<CatalystNewsItem[]>([]);
  const [events, setEvents] = useState<CatalystEvent[]>([]);
  const [themes, setThemes] = useState<ThemeCatalystScore[]>([]);
  const [loading, setLoading] = useState(true);
  const [statusFilter, setStatusFilter] = useState("all");

  const loadData = useCallback(async () => {
    try {
      const [newsData, eventData, themeData] = await Promise.all([
        fetchAPI<CatalystNewsItem[]>("/api/catalysts/news?limit=80&hours=72").catch(() => []),
        fetchAPI<CatalystEvent[]>("/api/catalysts/recent?limit=60&hours=72").catch(() => []),
        fetchAPI<ThemeCatalystScore[]>("/api/catalysts/theme-scores?limit=20&hours=72").catch(() => []),
      ]);
      setNews(newsData);
      setEvents(eventData);
      setThemes(themeData);
    } finally {
      setLoading(false);
    }
  }, []);

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

  useWebSocket(
    useCallback((message: { type: string }) => {
      if (message.type === "news_catalysts_ready" || message.type === "sector_scan_ready" || message.type === "scan_complete") {
        loadData();
      }
    }, [loadData])
  );

  const analyzedCount = news.filter((item) => item.status === "analyzed").length;
  const pendingCount = news.filter((item) => item.status === "pending").length;
  const failedCount = news.filter((item) => item.status === "failed").length;
  const topTheme = themes[0];
  const headline = buildSentimentHeadline(themes, events);

  const filteredNews = useMemo(() => {
    if (statusFilter === "all") return news;
    return news.filter((item) => item.status === statusFilter);
  }, [news, statusFilter]);

  const eventsById = useMemo(() => {
    const map = new Map<number, CatalystEvent>();
    events.forEach((event) => map.set(event.id, event));
    return map;
  }, [events]);

  return (
    <ErrorBoundary>
      <div className="max-w-7xl mx-auto px-4 md:px-8 pt-6 pb-20 md:pb-10 space-y-5">
        <div className="animate-fade-in-up">
          <h1 className="text-lg font-bold tracking-tight">舆情雷达</h1>
        </div>

        <div className="grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_340px] gap-4 animate-fade-in-up">
          <section className="glass-card-static p-4 md:p-5">
            <div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
              <div className="min-w-0">
                <div className="text-[10px] uppercase tracking-[0.22em] text-amber-400 font-semibold">市场情绪线索</div>
                <h2 className="mt-2 text-xl font-bold tracking-tight text-text-primary">{headline.title}</h2>
                <p className="mt-2 max-w-3xl text-sm leading-6 text-text-secondary">{headline.detail}</p>
              </div>
              <div className="grid grid-cols-2 gap-2 md:w-[280px] shrink-0">
                <RadarMetric label="已分析" value={analyzedCount} tone="hot" />
                <RadarMetric label="待处理" value={pendingCount} tone="warm" />
                <RadarMetric label="强主题" value={themes.filter((item) => item.catalyst_score >= 70).length} tone="hot" />
                <RadarMetric label="异常" value={failedCount} tone={failedCount ? "warm" : "quiet"} />
              </div>
            </div>

            <div className="mt-4 grid grid-cols-1 md:grid-cols-3 gap-3">
              <RadarDecision title="当前重点" value={topTheme?.theme_name ?? "暂无"} detail={topTheme ? `催化分 ${topTheme.catalyst_score.toFixed(0)}，${topTheme.catalyst_count} 条线索` : "等待后台新闻归因。"} tone="hot" />
              <RadarDecision title="观察方式" value={headline.action} detail="只作为主题热度和催化背景，不直接生成买卖结论。" tone="warm" />
              <RadarDecision title="失效信号" value={headline.risk} detail="当新闻无法映射到资金主线时，降低权重。" tone="quiet" />
            </div>
          </section>

          <section className="glass-card-static p-4">
            <div className="flex items-center justify-between gap-3">
              <h2 className="text-sm font-semibold text-text-primary">主题催化排行</h2>
              <span className="text-[10px] text-text-muted">72小时</span>
            </div>
            <div className="mt-3 space-y-2.5">
              {themes.length ? themes.slice(0, 8).map((theme, index) => (
                <ThemePulseRow key={theme.theme_id} theme={theme} rank={index + 1} />
              )) : (
                <EmptyLine text={loading ? "加载舆情主题..." : "暂无主题催化"} />
              )}
            </div>
          </section>
        </div>

        <div className="grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_380px] gap-4 animate-fade-in-up">
          <section className="glass-card-static p-4 md:p-5">
            <div className="flex flex-wrap items-center justify-between gap-3">
              <div>
                <h2 className="text-sm font-semibold text-text-primary">舆情流</h2>
                <p className="mt-1 text-xs text-text-muted">后台抓取的新闻、政策和公告线索。</p>
              </div>
              <div className="flex flex-wrap gap-2">
                {[
                  { key: "all", label: "全部", count: news.length },
                  { key: "analyzed", label: "已归因", count: analyzedCount },
                  { key: "pending", label: "待处理", count: pendingCount },
                  { key: "failed", label: "异常", count: failedCount },
                ].map((tab) => (
                  <button
                    key={tab.key}
                    onClick={() => setStatusFilter(tab.key)}
                    className={`rounded-lg border px-3 py-1.5 text-xs font-medium transition-all ${
                      statusFilter === tab.key
                        ? "border-amber-500/20 bg-amber-500/10 text-amber-300"
                        : "border-border-subtle bg-surface-1 text-text-muted hover:text-text-primary"
                    }`}
                  >
                    {tab.label} {tab.count}
                  </button>
                ))}
              </div>
            </div>

            <div className="mt-4 space-y-3">
              {filteredNews.length ? filteredNews.map((item) => (
                <NewsRow key={item.id} item={item} event={item.catalyst_id ? eventsById.get(item.catalyst_id) : undefined} />
              )) : (
                <div className="rounded-2xl border border-border-subtle bg-surface-1/70 p-8 text-center text-sm text-text-muted">
                  {loading ? "加载舆情流..." : "暂无符合条件的舆情。"}
                </div>
              )}
            </div>
          </section>

          <aside className="space-y-4">
            <section className="glass-card-static p-4">
              <h2 className="text-sm font-semibold text-text-primary">AI 归因摘要</h2>
              <div className="mt-3 space-y-3">
                {events.length ? events.slice(0, 6).map((event) => (
                  <CatalystInsight key={event.id} event={event} />
                )) : (
                  <EmptyLine text={loading ? "加载归因结果..." : "暂无 AI 归因结果"} />
                )}
              </div>
            </section>

            <section className="glass-card-static p-4">
              <h2 className="text-sm font-semibold text-text-primary">使用边界</h2>
              <div className="mt-3 space-y-2 text-xs leading-6 text-text-secondary">
                <BoundaryLine text="舆情只解释催化方向，不直接给出买卖。" />
                <BoundaryLine text="主题催化需要和资金流、前排强度共同确认。" />
                <BoundaryLine text="页面只读取本地数据库，不触发外部抓取。" />
              </div>
            </section>
          </aside>
        </div>
      </div>
    </ErrorBoundary>
  );
}

function buildSentimentHeadline(themes: ThemeCatalystScore[], events: CatalystEvent[]) {
  const top = themes[0];
  const strongCount = themes.filter((item) => item.catalyst_score >= 70).length;
  const policyCount = events.filter((item) => item.catalyst_type === "policy").length;

  if (!top) {
    return {
      title: "舆情等待后台归因",
      detail: "新闻采集和催化分析会在后台任务完成后更新。",
      action: "等待线索",
      risk: "无数据不判断",
    };
  }

  if (top.catalyst_score >= 75) {
    return {
      title: `${top.theme_name} 舆情升温`,
      detail: `过去 72 小时 ${top.catalyst_count} 条催化线索，${strongCount} 个主题达到强催化阈值。${policyCount ? `其中政策类线索 ${policyCount} 条。` : ""}`,
      action: "优先核对资金回流",
      risk: "热度兑现",
    };
  }

  return {
    title: `${top.theme_name} 有线索但未形成强共振`,
    detail: `当前催化分 ${top.catalyst_score.toFixed(0)}，更适合观察是否被资金和板块前排确认。`,
    action: "跟踪扩散",
    risk: "证据不足",
  };
}

function RadarMetric({ label, value, tone }: { label: string; value: number; tone: CatalystTone }) {
  const toneClass = getToneClass(tone);
  return (
    <div className={`rounded-xl border px-3 py-2 ${toneClass.box}`}>
      <div className="text-[10px] text-text-muted">{label}</div>
      <div className={`mt-1 font-mono text-xl font-bold tabular-nums ${toneClass.text}`}>{value}</div>
    </div>
  );
}

function RadarDecision({ title, value, detail, tone }: { title: string; value: string; detail: string; tone: CatalystTone }) {
  const toneClass = getToneClass(tone);
  return (
    <div className={`rounded-2xl border p-3 ${toneClass.box}`}>
      <div className="text-[11px] font-semibold text-text-secondary">{title}</div>
      <div className={`mt-1 text-sm font-bold ${toneClass.text}`}>{value}</div>
      <div className="mt-1 text-xs leading-5 text-text-muted">{detail}</div>
    </div>
  );
}

function ThemePulseRow({ theme, rank }: { theme: ThemeCatalystScore; rank: number }) {
  const score = Math.max(0, Math.min(theme.catalyst_score, 100));
  const tone = score >= 70 ? "hot" : score >= 45 ? "warm" : "quiet";
  const toneClass = getToneClass(tone);

  return (
    <div className="rounded-xl border border-border-subtle bg-surface-1/70 px-3 py-3">
      <div className="flex items-start justify-between gap-3">
        <div className="min-w-0 flex gap-3">
          <div className={`flex h-7 w-7 shrink-0 items-center justify-center rounded-lg border font-mono text-xs ${toneClass.box} ${toneClass.text}`}>
            {rank}
          </div>
          <div className="min-w-0">
            <div className="text-sm font-semibold text-text-primary">{theme.theme_name}</div>
            <div className="mt-1 text-[11px] text-text-muted line-clamp-1">
              {theme.top_reasons?.[0] ?? "等待更多舆情证据"}
            </div>
          </div>
        </div>
        <div className={`font-mono text-sm font-bold tabular-nums ${toneClass.text}`}>{score.toFixed(0)}</div>
      </div>
      <div className="mt-3 h-1.5 rounded-full bg-surface-2 overflow-hidden">
        <div className={`h-full rounded-full ${toneClass.bar}`} style={{ width: `${score}%` }} />
      </div>
    </div>
  );
}

function NewsRow({ item, event }: { item: CatalystNewsItem; event?: CatalystEvent }) {
  const status = getStatusMeta(item.status);
  const eventTone = event ? getEventTone(event) : "quiet";
  const toneClass = getToneClass(eventTone);
  const title = event?.title || item.title;
  const href = item.url || event?.url || "";

  return (
    <article className="rounded-2xl border border-border-subtle bg-surface-1/70 p-4 transition-colors hover:border-amber-500/15">
      <div className="flex flex-col gap-3 md:flex-row md:items-start md:justify-between">
        <div className="min-w-0">
          <div className="flex flex-wrap items-center gap-2">
            <span className={`rounded-md border px-2 py-0.5 text-[10px] ${status.className}`}>{status.label}</span>
            <span className="text-[10px] text-text-muted">{formatSource(item.source)}</span>
            <span className="text-[10px] text-text-muted">{formatDateTime(item.published_at || item.created_at)}</span>
          </div>
          {href ? (
            <a href={href} target="_blank" rel="noreferrer" className="mt-2 block text-sm font-semibold leading-6 text-text-primary hover:text-amber-300">
              {title}
            </a>
          ) : (
            <h3 className="mt-2 text-sm font-semibold leading-6 text-text-primary">{title}</h3>
          )}
          {event?.summary || event?.llm_reason ? (
            <p className="mt-2 text-xs leading-6 text-text-secondary line-clamp-2">
              {event.llm_reason || event.summary}
            </p>
          ) : item.error ? (
            <p className="mt-2 text-xs leading-6 text-amber-300/80 line-clamp-2">{item.error}</p>
          ) : null}
        </div>

        <div className="grid grid-cols-3 gap-2 md:w-[240px] shrink-0">
          <MiniScore label="强度" value={event?.strength} tone={eventTone} />
          <MiniScore label="新鲜" value={event?.freshness} tone={eventTone} />
          <MiniScore label="可信" value={event?.confidence} tone={eventTone} />
        </div>
      </div>
      {event?.themes ? (
        <div className="mt-3 rounded-xl border border-border-subtle bg-surface-2/70 px-3 py-2 text-[11px] leading-5 text-text-secondary">
          归因：{event.themes}
        </div>
      ) : null}
      {event ? (
        <div className="mt-3 flex flex-wrap gap-2">
          <span className={`rounded-md border px-2 py-1 text-[10px] ${toneClass.box} ${toneClass.text}`}>{formatCatalystType(event.catalyst_type)}</span>
          <span className="rounded-md border border-border-subtle bg-surface-2 px-2 py-1 text-[10px] text-text-muted">本地已归档</span>
        </div>
      ) : null}
    </article>
  );
}

function CatalystInsight({ event }: { event: CatalystEvent }) {
  const tone = getEventTone(event);
  const toneClass = getToneClass(tone);
  return (
    <div className="rounded-xl border border-border-subtle bg-surface-1/70 px-3 py-3">
      <div className="flex items-start justify-between gap-3">
        <div className="min-w-0">
          <div className="flex flex-wrap items-center gap-2">
            <span className={`rounded-md border px-2 py-0.5 text-[10px] ${toneClass.box} ${toneClass.text}`}>{formatCatalystType(event.catalyst_type)}</span>
            <span className="text-[10px] text-text-muted">{formatDateTime(event.published_at || event.created_at)}</span>
          </div>
          <div className="mt-2 text-sm font-semibold leading-6 text-text-primary line-clamp-2">{event.title}</div>
          <div className="mt-1 text-xs leading-5 text-text-secondary line-clamp-3">
            {event.llm_reason || event.summary || "等待更多解释"}
          </div>
        </div>
        <div className={`font-mono text-sm font-bold tabular-nums ${toneClass.text}`}>{Math.round(event.strength)}</div>
      </div>
    </div>
  );
}

function MiniScore({ label, value, tone }: { label: string; value?: number; tone: CatalystTone }) {
  const toneClass = getToneClass(tone);
  return (
    <div className="rounded-lg bg-surface-2 px-2 py-1.5">
      <div className="text-[10px] text-text-muted">{label}</div>
      <div className={`mt-0.5 font-mono text-xs font-semibold tabular-nums ${value == null ? "text-text-muted" : toneClass.text}`}>
        {value == null ? "--" : Math.round(value)}
      </div>
    </div>
  );
}

function BoundaryLine({ text }: { text: string }) {
  return (
    <div className="flex items-start gap-2">
      <span className="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-amber-400" />
      <span>{text}</span>
    </div>
  );
}

function EmptyLine({ text }: { text: string }) {
  return (
    <div className="rounded-xl border border-border-subtle bg-surface-1/70 px-3 py-4 text-center text-xs text-text-muted">
      {text}
    </div>
  );
}

function getToneClass(tone: CatalystTone) {
  if (tone === "hot") {
    return {
      box: "border-red-500/15 bg-red-500/[0.08]",
      text: "text-red-300",
      bar: "bg-red-400",
    };
  }
  if (tone === "warm") {
    return {
      box: "border-amber-500/15 bg-amber-500/[0.08]",
      text: "text-amber-300",
      bar: "bg-amber-400",
    };
  }
  return {
    box: "border-border-subtle bg-surface-2",
    text: "text-text-secondary",
    bar: "bg-text-muted",
  };
}

function getEventTone(event: CatalystEvent): CatalystTone {
  if (event.strength >= 70 || event.confidence >= 75) return "hot";
  if (event.strength >= 45 || event.freshness >= 55) return "warm";
  return "quiet";
}

function getStatusMeta(status: string) {
  if (status === "analyzed") {
    return { label: "已归因", className: "border-emerald-500/15 bg-emerald-500/10 text-emerald-300" };
  }
  if (status === "pending") {
    return { label: "待处理", className: "border-amber-500/15 bg-amber-500/10 text-amber-300" };
  }
  if (status === "failed") {
    return { label: "异常", className: "border-red-500/15 bg-red-500/10 text-red-300" };
  }
  if (status === "skipped") {
    return { label: "已忽略", className: "border-border-subtle bg-surface-2 text-text-muted" };
  }
  return { label: status || "未知", className: "border-border-subtle bg-surface-2 text-text-muted" };
}

function formatCatalystType(type: string) {
  const labels: Record<string, string> = {
    policy: "政策",
    industry: "产业",
    event: "事件",
    earnings: "业绩",
    announcement: "公告",
    news: "新闻",
  };
  return labels[type] ?? type;
}

function formatSource(source: string) {
  if (!source) return "未知来源";
  return source.replace("tushare:", "").replace("rss:", "");
}

function formatDateTime(value?: string | null) {
  if (!value) return "暂无时间";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleString("zh-CN", {
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
  });
}
