import { useEffect, useMemo, useState } from 'react';
import { Line } from '@ant-design/charts';
import { Spin, Typography, Tag } from 'antd';
import { LineChartOutlined, CloseOutlined, WarningOutlined } from '@ant-design/icons';
import { healthDataApi } from '../../../api/health/healthData';
import { useThemeMode } from '../../../hooks/useThemeMode';

const { Text } = Typography;

// ---------------------------------------------------------------------------
// 统计计算工具函数（与后端 trend_stats.rs 对齐）
// ---------------------------------------------------------------------------

/** 最小二乘法线性回归 */
function linearRegression(points: { date: string; value: number }[]) {
  const n = points.length;
  if (n < 2) return null;

  const xs = points.map((_, i) => i);
  const ys = points.map((p) => p.value);

  const sumX = xs.reduce((a, b) => a + b, 0);
  const sumY = ys.reduce((a, b) => a + b, 0);
  const sumXY = xs.reduce((acc, x, i) => acc + x * ys[i], 0);
  const sumX2 = xs.reduce((acc, x) => acc + x * x, 0);

  const denom = n * sumX2 - sumX * sumX;
  if (Math.abs(denom) < 1e-10) return null;

  const slope = (n * sumXY - sumX * sumY) / denom;
  const intercept = (sumY - slope * sumX) / n;

  const meanY = sumY / n;
  const ssTot = ys.reduce((acc, y) => acc + (y - meanY) ** 2, 0);
  const rSquared = ssTot > 0 ? 1 - ys.reduce((acc, y, i) => acc + (y - (intercept + slope * i)) ** 2, 0) / ssTot : 1;

  return { slope, intercept, rSquared };
}

/** 移动平均 */
function movingAverage(values: number[], window: number): (number | null)[] {
  if (values.length === 0 || window === 0) return [];
  return values.map((_, i) => {
    if (i + 1 < window) return null;
    const slice = values.slice(i + 1 - window, i + 1);
    return slice.reduce((a, b) => a + b, 0) / window;
  });
}

/** 异常检测 */
function detectAnomalies(points: { date: string; value: number }[], threshold: number) {
  if (points.length < 3) return new Set<number>();

  const values = points.map((p) => p.value);
  const n = values.length;
  const mean = values.reduce((a, b) => a + b, 0) / n;
  const variance = values.reduce((acc, v) => acc + (v - mean) ** 2, 0) / n;
  const stdDev = Math.sqrt(variance);

  if (stdDev < 1e-10) return new Set<number>();

  const anomalies = new Set<number>();
  values.forEach((v, i) => {
    if (Math.abs((v - mean) / stdDev) > threshold) {
      anomalies.add(i);
    }
  });
  return anomalies;
}

// ---------------------------------------------------------------------------
// 组件
// ---------------------------------------------------------------------------

interface Props {
  patientId: string;
  refreshKey?: number;
}

interface MetricConfig {
  key: string;
  label: string;
  unit: string;
  color: string;
  normalRange?: [number, number];
}

const METRICS: MetricConfig[] = [
  { key: 'systolic_bp_morning', label: '收缩压(晨)', unit: 'mmHg', color: '#ef4444', normalRange: [90, 140] },
  { key: 'diastolic_bp_morning', label: '舒张压(晨)', unit: 'mmHg', color: '#f97316', normalRange: [60, 90] },
  { key: 'heart_rate', label: '心率', unit: 'bpm', color: '#3b82f6', normalRange: [60, 100] },
  { key: 'weight', label: '体重', unit: 'kg', color: '#10b981' },
  { key: 'blood_sugar', label: '血糖', unit: 'mmol/L', color: '#8b5cf6', normalRange: [3.9, 6.1] },
];

interface MetricData {
  points: { date: string; value: number }[];
  latest: number | null;
}

function extractData(res: unknown): { date: string; value: number }[] {
  const raw = (res as { data?: { date: string; value: number }[] })?.data;
  const arr = Array.isArray(res) ? res : Array.isArray(raw) ? raw : [];
  return arr.filter((d) => d?.value != null);
}

const emptyData: MetricData = { points: [], latest: null };

/** 概览卡片 — 指标名 + 最新值 + 趋势方向 + 微型趋势线 */
function MetricCard({
  metric,
  metricData,
  selected,
  onClick,
  trendDirection,
  anomalyCount,
}: {
  metric: MetricConfig;
  metricData: MetricData;
  selected: boolean;
  onClick: () => void;
  trendDirection: 'rising' | 'falling' | 'stable' | null;
  anomalyCount: number;
}) {
  const hasData = metricData.points.length > 0;
  const cardStyle: React.CSSProperties = {
    minWidth: 130,
    padding: '8px 12px',
    background: 'var(--ant-color-bg-container, #fafafa)',
    borderRadius: 8,
    border: selected
      ? `2px solid ${metric.color}`
      : '1px solid var(--ant-color-border-secondary, #f0f0f0)',
    cursor: hasData ? 'pointer' : 'default',
    transition: 'border-color 0.2s, box-shadow 0.2s',
    flex: '0 0 auto',
    ...(selected && hasData ? { boxShadow: `0 0 0 1px ${metric.color}22` } : {}),
  };

  const directionIcon = trendDirection === 'rising' ? '↑' : trendDirection === 'falling' ? '↓' : '→';
  const directionColor = trendDirection === 'rising' ? '#ef4444' : trendDirection === 'falling' ? '#3b82f6' : '#94a3b8';

  return (
    <div style={cardStyle} onClick={hasData ? onClick : undefined}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 2 }}>
        <Text style={{ fontSize: 11, color: 'var(--ant-color-text-secondary)' }}>{metric.label}</Text>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          {anomalyCount > 0 && (
            <WarningOutlined style={{ fontSize: 10, color: '#ef4444' }} />
          )}
          {trendDirection && (
            <span style={{ fontSize: 11, color: directionColor, fontWeight: 600 }}>{directionIcon}</span>
          )}
          {metricData.latest != null && (
            <Text style={{ fontSize: 12, fontWeight: 600, color: metric.color }}>
              {metricData.latest}
              <span style={{ fontWeight: 400, fontSize: 10, marginLeft: 2 }}>{metric.unit}</span>
            </Text>
          )}
        </div>
      </div>
      {hasData ? (
        <Line
          data={metricData.points}
          xField="date"
          yField="value"
          smooth
          height={32}
          axis={false}
          point={false}
          style={{ lineWidth: 1.5, stroke: metric.color }}
          tooltip={false}
        />
      ) : (
        <div style={{ height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Text type="secondary" style={{ fontSize: 10 }}>暂无数据</Text>
        </div>
      )}
    </div>
  );
}

export function VitalSignsChart({ patientId, refreshKey }: Props) {
  const [metricsData, setMetricsData] = useState<Record<string, MetricData>>({});
  const [loading, setLoading] = useState(true);
  const [selectedKey, setSelectedKey] = useState<string | null>(null);
  const isDark = useThemeMode();

  useEffect(() => {
    if (!patientId) return;
    setLoading(true);

    Promise.allSettled(
      METRICS.map((m) =>
        healthDataApi
          .getIndicatorTimeseries(patientId, m.key)
          .then(extractData)
          .then((points) => ({
            key: m.key,
            data: { points, latest: points.length > 0 ? points[points.length - 1].value : null },
          }))
      )
    ).then((results) => {
      const map: Record<string, MetricData> = {};
      results.forEach((r, i) => {
        if (r.status === 'fulfilled') {
          map[r.value.key] = r.value.data;
        } else {
          map[METRICS[i].key] = emptyData;
        }
      });
      setMetricsData(map);
      setLoading(false);
    });
  }, [patientId, refreshKey]);

  // 趋势统计 — 所有 hooks 必须在 early return 之前调用
  const trendStats = useMemo(() => {
    const stats: Record<string, {
      regression: ReturnType<typeof linearRegression>;
      ma: (number | null)[];
      anomalyIndices: Set<number>;
    }> = {};

    for (const m of METRICS) {
      const data = metricsData[m.key];
      if (!data || data.points.length < 2) {
        stats[m.key] = { regression: null, ma: [], anomalyIndices: new Set() };
        continue;
      }

      const regression = linearRegression(data.points);
      const values = data.points.map((p) => p.value);
      const maWindow = Math.min(7, Math.max(3, Math.floor(values.length / 3)));
      const ma = movingAverage(values, maWindow);
      const anomalyIndices = detectAnomalies(data.points, 2.0);

      stats[m.key] = { regression, ma, anomalyIndices };
    }
    return stats;
  }, [metricsData]);

  const selectedMetric = METRICS.find((m) => m.key === selectedKey);
  const selectedData = selectedKey ? metricsData[selectedKey] : null;
  const axisLabelStyle = { fill: isDark ? '#94a3b8' : '#475569' };

  const chartSeries = useMemo(() => {
    if (!selectedKey || !selectedData) return [];
    const stat = trendStats[selectedKey];
    if (!stat) return [];

    const points = selectedData.points;
    const series: { date: string; value: number; series: string; isAnomaly?: boolean }[] = [];

    points.forEach((p, i) => {
      series.push({
        date: p.date,
        value: p.value,
        series: '实际值',
        isAnomaly: stat.anomalyIndices.has(i),
      });
    });

    stat.ma.forEach((val, i) => {
      if (val != null) {
        series.push({
          date: points[i].date,
          value: val,
          series: '移动平均',
        });
      }
    });

    if (stat.regression) {
      const { intercept, slope } = stat.regression;
      points.forEach((p, i) => {
        series.push({
          date: p.date,
          value: intercept + slope * i,
          series: '趋势线',
        });
      });
    }

    return series;
  }, [selectedKey, selectedData, trendStats]);

  const getTrendDirection = (key: string): 'rising' | 'falling' | 'stable' | null => {
    const stat = trendStats[key];
    if (!stat?.regression) return null;
    const { slope } = stat.regression;
    if (Math.abs(slope) < 0.01) return 'stable';
    return slope > 0 ? 'rising' : 'falling';
  };

  const trendDescription = useMemo(() => {
    if (!selectedKey || !selectedData || !trendStats[selectedKey]) return null;
    const stat = trendStats[selectedKey];
    if (!stat?.regression) return null;

    const { slope, rSquared } = stat.regression;
    const direction = getTrendDirection(selectedKey);
    const anomalyCount = stat.anomalyIndices.size;
    const points = selectedData.points;
    const totalChange = slope * (points.length - 1);

    return {
      direction: direction === 'rising' ? '上升' : direction === 'falling' ? '下降' : '平稳',
      slope,
      rSquared,
      totalChange,
      periodDays: points.length > 1 ? points.length : 0,
      anomalyCount,
    };
  }, [selectedKey, selectedData, trendStats]);

  // Early returns — 放在所有 hooks 之后
  if (loading) {
    return (
      <div style={{ height: 48, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Spin size="small" />
      </div>
    );
  }

  const hasAnyData = Object.values(metricsData).some((d) => d.points.length > 0);
  if (!hasAnyData) {
    return (
      <div style={{
        height: 48,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        background: 'var(--ant-color-bg-container, #fafafa)',
        borderRadius: 6,
        border: '1px dashed var(--ant-color-border, #d9d9d9)',
      }}>
        <LineChartOutlined style={{ fontSize: 14, color: '#bfbfbf', marginRight: 6 }} />
        <Text type="secondary" style={{ fontSize: 12 }}>暂无趋势数据</Text>
      </div>
    );
  }

  return (
    <div>
      {/* 概览卡片条 */}
      <div style={{ display: 'flex', gap: 8, overflowX: 'auto', paddingBottom: 4 }}>
        {METRICS.map((m) => (
          <MetricCard
            key={m.key}
            metric={m}
            metricData={metricsData[m.key] ?? emptyData}
            selected={selectedKey === m.key}
            onClick={() => setSelectedKey((prev) => (prev === m.key ? null : m.key))}
            trendDirection={getTrendDirection(m.key)}
            anomalyCount={trendStats[m.key]?.anomalyIndices.size ?? 0}
          />
        ))}
      </div>

      {/* 详情图区域 */}
      {selectedMetric && selectedData && selectedData.points.length > 0 && (
        <div style={{
          marginTop: 12,
          padding: 16,
          background: 'var(--ant-color-bg-container, #fafafa)',
          borderRadius: 8,
          border: '1px solid var(--ant-color-border-secondary, #f0f0f0)',
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
              <Text style={{ fontSize: 14, fontWeight: 600 }}>{selectedMetric.label}</Text>
              <Text style={{ fontSize: 18, fontWeight: 700, color: selectedMetric.color }}>
                {selectedData.latest}
              </Text>
              <Text type="secondary" style={{ fontSize: 12 }}>{selectedMetric.unit}</Text>
              {trendDescription && (
                <Tag color={
                  trendDescription.direction === '上升' ? 'red' :
                  trendDescription.direction === '下降' ? 'blue' : 'default'
                } style={{ marginLeft: 4, fontSize: 11 }}>
                  {trendDescription.direction} ({trendDescription.totalChange > 0 ? '+' : ''}{trendDescription.totalChange.toFixed(1)})
                </Tag>
              )}
            </div>
            <div
              onClick={() => setSelectedKey(null)}
              style={{ cursor: 'pointer', padding: '2px 6px', borderRadius: 4, color: 'var(--ant-color-text-secondary)' }}
            >
              <CloseOutlined style={{ fontSize: 12 }} />
            </div>
          </div>

          {/* 趋势统计摘要 */}
          {trendDescription && (
            <div style={{ display: 'flex', gap: 12, marginBottom: 8, flexWrap: 'wrap' }}>
              <Text type="secondary" style={{ fontSize: 11 }}>
                趋势斜率: {trendDescription.slope > 0 ? '+' : ''}{trendDescription.slope.toFixed(2)}/{selectedMetric.unit}/天
              </Text>
              <Text type="secondary" style={{ fontSize: 11 }}>
                R²: {trendDescription.rSquared.toFixed(3)}
              </Text>
              {trendDescription.anomalyCount > 0 && (
                <Text style={{ fontSize: 11, color: '#ef4444' }}>
                  <WarningOutlined style={{ marginRight: 2 }} />
                  {trendDescription.anomalyCount} 个异常点
                </Text>
              )}
            </div>
          )}

          <Line
            data={chartSeries}
            xField="date"
            yField="value"
            colorField="series"
            height={240}
            axis={{
              x: { labelAutoRotate: true, label: { style: axisLabelStyle } },
              y: { title: selectedMetric.unit, label: { style: axisLabelStyle } },
            }}
            style={{
              lineWidth: (datum: Record<string, unknown>) => {
                const series = datum.series as string;
                if (series === '趋势线') return 1.5;
                if (series === '移动平均') return 2;
                return 2.5;
              },
              stroke: (datum: Record<string, unknown>) => {
                const series = datum.series as string;
                if (series === '趋势线') return '#f59e0b';
                if (series === '移动平均') return '#14b8a6';
                return selectedMetric.color;
              },
              lineDash: (datum: Record<string, unknown>) => {
                const series = datum.series as string;
                if (series === '趋势线') return [8, 4];
                if (series === '移动平均') return [4, 2];
                return [];
              },
            }}
            point={{
              shapeField: 'circle',
              sizeField: 4,
              style: {
                fill: (datum: Record<string, unknown>) => {
                  if (datum.isAnomaly) return '#ef4444';
                  return selectedMetric.color;
                },
                r: (datum: Record<string, unknown>) => {
                  if (datum.isAnomaly) return 5;
                  return 3;
                },
              },
            }}
            tooltip={{
              title: (d: Record<string, unknown>) => d.date as string,
              items: [{ channel: 'y', valueFormatter: (v: number) => `${v} ${selectedMetric.unit}` }],
            }}
          />

          {/* 图例说明 */}
          <div style={{ display: 'flex', gap: 16, marginTop: 4, justifyContent: 'center' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
              <div style={{ width: 16, height: 2.5, background: selectedMetric.color, borderRadius: 1 }} />
              <Text type="secondary" style={{ fontSize: 10 }}>实际值</Text>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
              <div style={{ width: 16, height: 2, background: '#14b8a6', borderRadius: 1, backgroundRepeat: 'repeat-x', backgroundImage: 'linear-gradient(#14b8a6, #14b8a6)', backgroundSize: '4px 2px', backgroundPosition: '0 0' }} />
              <Text type="secondary" style={{ fontSize: 10 }}>移动平均</Text>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
              <div style={{ width: 16, borderTop: '2px dashed #f59e0b' }} />
              <Text type="secondary" style={{ fontSize: 10 }}>趋势线</Text>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
              <div style={{ width: 8, height: 8, borderRadius: '50%', background: '#ef4444' }} />
              <Text type="secondary" style={{ fontSize: 10 }}>异常点</Text>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
