import { useEffect, useState, useMemo } from 'react';
import { Activity } from 'lucide-react';
import { caseApi, riskApi, alertApi, envApi } from '@/services/api';
import { ErrorBanner } from '@/components/ErrorBanner';
import { LoadingState, Segmented } from '@/components/ui';
import { TESTIDS } from '@/utils/testids';
import type {
  CaseTrendPoint,
  DistrictCaseData,
  PollutantPoint,
  DiagnosisBreakdown,
  Alert,
} from '@/types';
import { KpiRow, type KpiData } from '@/components/overview/KpiRow';
import { CaseAqiTrend, type MergedTrendItem } from '@/components/overview/CaseAqiTrend';
import { DistrictChoropleth } from '@/components/overview/DistrictChoropleth';
import { TopDistrictsBar } from '@/components/overview/TopDistrictsBar';
import { TopDiagnosesBar } from '@/components/overview/TopDiagnosesBar';
import { AlertSeverityDonut, type AlertSlice } from '@/components/overview/AlertSeverityDonut';
import { CHART_COLORS } from '@/components/overview/chartColors';
import {
  joinDistrictCases,
  buildMetricLookup,
  type MetricKey,
} from '@/components/overview/districtNormalize';

const METRIC_OPTIONS: { value: MetricKey; label: string }[] = [
  { value: 'all', label: '全部' },
  { value: 'outpatient', label: '门诊' },
  { value: 'inpatient', label: '住院' },
];

const METRIC_LABEL: Record<MetricKey, string> = {
  all: '病例',
  outpatient: '门诊',
  inpatient: '住院',
};

function computeChangeRatio(trend: CaseTrendPoint[]): number | null {
  if (trend.length < 8) return null;
  const recent7 = trend.slice(-7).reduce((s, p) => s + p.total, 0);
  const prior7 = trend.slice(-14, -7).reduce((s, p) => s + p.total, 0);
  if (prior7 === 0) return null;
  return ((recent7 - prior7) / prior7) * 100;
}

export function OverviewDashboard() {
  const [kpi, setKpi] = useState<KpiData | null>(null);
  const [mergedTrend, setMergedTrend] = useState<MergedTrendItem[]>([]);
  const [districts, setDistricts] = useState<DistrictCaseData[]>([]);
  const [topDiagnoses, setTopDiagnoses] = useState<DiagnosisBreakdown[]>([]);
  const [alertPie, setAlertPie] = useState<AlertSlice[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [errors, setErrors] = useState<string[]>([]);

  // 门诊/住院/全部 — 同时驱动 choropleth 与 Top5 区县条形图。
  const [metric, setMetric] = useState<MetricKey>('all');

  useEffect(() => {
    let cancelled = false;

    const fetchAll = async () => {
      setIsLoading(true);
      setErrors([]);

      const now = new Date();
      const endStr = now.toISOString().split('T')[0];
      const start14 = new Date(now);
      start14.setDate(start14.getDate() - 14);
      const start14Str = start14.toISOString().split('T')[0];
      const start30 = new Date(now);
      start30.setDate(start30.getDate() - 30);
      const start30Str = start30.toISOString().split('T')[0];

      // KPI sources — Promise.allSettled to survive individual failures.
      const [statsR, trend14R, alertsR, riskStatsR, pollutantsR] = await Promise.allSettled([
        caseApi.getStats(),
        caseApi.getTrend({ start_date: start14Str, end_date: endStr, group_by: 'day' }),
        alertApi.getAlerts(),
        riskApi.getStats(),
        envApi.getPollutants(7),
      ]);

      // Trend + district sources.
      const [trend30R, districtsR, diagStatsR] = await Promise.allSettled([
        caseApi.getTrend({ start_date: start30Str, end_date: endStr, group_by: 'day' }),
        caseApi.getDistricts(),
        caseApi.getStats(), // reuse for top_diagnoses
      ]);

      if (cancelled) return;

      const newErrors: string[] = [];

      // --- KPI ---
      let totalCases = 0;
      if (statsR.status === 'fulfilled') {
        const s = statsR.value;
        totalCases = (s.total_outpatient || 0) + (s.total_inpatient || 0);
      } else {
        newErrors.push('累计病例数据加载失败');
      }

      let todayCases = 0;
      let changeRatio: number | null = null;
      if (trend14R.status === 'fulfilled') {
        const trend = trend14R.value.trend || [];
        if (trend.length > 0) todayCases = trend[trend.length - 1].total;
        changeRatio = computeChangeRatio(trend);
      } else {
        newErrors.push('今日病例数据加载失败');
      }

      let activeAlerts = 0;
      let alertList: Alert[] = [];
      if (alertsR.status === 'fulfilled') {
        alertList = alertsR.value.alerts || [];
        activeAlerts = alertList.length;
      } else {
        newErrors.push('预警数据加载失败');
      }

      let highRiskGrids = 0;
      if (riskStatsR.status === 'fulfilled') {
        highRiskGrids = riskStatsR.value.high_risk_count || 0;
      } else {
        newErrors.push('风险网格数据加载失败');
      }

      let avgAQI = 0;
      let pollutantData: PollutantPoint[] = [];
      if (pollutantsR.status === 'fulfilled') {
        pollutantData = pollutantsR.value.data || [];
        if (pollutantData.length > 0) {
          const sumAQI = pollutantData.reduce((s, p) => s + (p.AQI || 0), 0);
          avgAQI = Math.round(sumAQI / pollutantData.length);
        }
      } else {
        newErrors.push('AQI数据加载失败');
      }

      setKpi({ totalCases, todayCases, changeRatio, activeAlerts, highRiskGrids, avgAQI });

      // --- Merge case trend + AQI ---
      if (trend30R.status === 'fulfilled') {
        const trend30 = trend30R.value.trend || [];
        const aqiMap: Record<string, number> = {};
        for (const p of pollutantData) aqiMap[p.date] = p.AQI || 0;
        setMergedTrend(
          trend30.map((t) => ({ date: t.date, cases: t.total, aqi: aqiMap[t.date] || 0 }))
        );
      } else if (!newErrors.includes('今日病例数据加载失败')) {
        newErrors.push('趋势数据加载失败');
      }

      // --- Districts (feeds choropleth + Top5 via normalize/join) ---
      if (districtsR.status === 'fulfilled') {
        setDistricts(districtsR.value.districts || []);
      } else {
        newErrors.push('区县数据加载失败');
      }

      // --- Top 5 Diagnoses ---
      if (diagStatsR.status === 'fulfilled') {
        const topDiag = diagStatsR.value.top_diagnoses || [];
        setTopDiagnoses(
          topDiag.slice(0, 5).map((d) => ({
            diagnosis: d.diagnosis,
            outpatient: d.outpatient,
            inpatient: d.inpatient,
            total: d.outpatient + d.inpatient,
          }))
        );
      }

      // --- Alert severity donut ---
      const p1 = alertList.filter((a) => a.priority === 'P1').length;
      const p2 = alertList.filter((a) => a.priority === 'P2').length;
      setAlertPie([
        { name: 'P1 紧急', value: p1, color: CHART_COLORS.alertP1 },
        { name: 'P2 关注', value: p2, color: CHART_COLORS.alertP2 },
      ]);

      setErrors(newErrors);
      setIsLoading(false);
    };

    fetchAll();
    return () => {
      cancelled = true;
    };
  }, []);

  // 归一并聚合到 13 区一次，供 choropleth 与 Top5 共享。
  const joinedDistricts = useMemo(() => joinDistrictCases(districts), [districts]);
  const metricLookup = useMemo(
    () => buildMetricLookup(joinedDistricts, metric),
    [joinedDistricts, metric]
  );

  if (isLoading) {
    return <LoadingState label="加载概览数据…" testid={TESTIDS.pageLoading} />;
  }

  return (
    <div data-testid={TESTIDS.pageOverview} className="flex flex-col h-full overflow-auto">
      {errors.length > 0 && (
        <div className="px-6 pt-4">
          <ErrorBanner
            error={errors.join('；')}
            onRetry={() => window.location.reload()}
            onDismiss={() => setErrors([])}
          />
        </div>
      )}

      <div className="p-6 space-y-6">
        {/* Page header + honesty badge + metric toggle */}
        <div className="flex flex-wrap items-start justify-between gap-3">
          <div>
            <h1 className="font-display text-[18px] font-semibold mb-1 flex items-center gap-2">
              <Activity className="w-5 h-5 text-primary" />
              综合概览
              <span
                data-testid={TESTIDS.asofBadge}
                className="ml-1 inline-flex items-center rounded-full bg-bg-hover px-2 py-0.5 text-[11px] font-medium text-text-secondary border border-border"
              >
                数据截至2023-12
              </span>
            </h1>
            <p className="text-[12px] text-text-secondary">病例、环境与预警关键指标总览</p>
          </div>
          <Segmented
            options={METRIC_OPTIONS}
            value={metric}
            onChange={setMetric}
            testid={TESTIDS.outinpatientToggle}
          />
        </div>

        {/* KPI Row */}
        <KpiRow kpi={kpi} />

        {/* Headline: Wuhan 13-district choropleth */}
        <div className="card p-4">
          <div className="text-[11px] font-medium text-text-secondary uppercase tracking-wide mb-3">
            武汉市13区{METRIC_LABEL[metric]}分布（高风险高亮）
          </div>
          <DistrictChoropleth
            metricLookup={metricLookup}
            metricLabel={`${METRIC_LABEL[metric]}数`}
          />
        </div>

        {/* Case + AQI trend */}
        <CaseAqiTrend data={mergedTrend} />

        {/* Top districts (metric-driven) + Top diagnoses */}
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
          <TopDistrictsBar
            districts={joinedDistricts}
            metric={metric}
            metricLabel={METRIC_LABEL[metric]}
          />
          <TopDiagnosesBar diagnoses={topDiagnoses} />
        </div>

        {/* Alert severity donut */}
        <AlertSeverityDonut data={alertPie} />
      </div>
    </div>
  );
}
