import { useEffect, useState, useMemo } from 'react';
import { Card, Col, Row, Segmented, Switch, DatePicker, Empty, Spin, Grid, App, Typography } from 'antd';
import {
  AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip,
  ResponsiveContainer,
} from 'recharts';
import dayjs from 'dayjs';
import { api } from '@/lib/api';
import MiniDonutChart from '@/components/dashboard/MiniDonutChart';
import type { VisitOutcome, CanvassOutcomeTrendsData } from '@/types/canvass';
import { VISIT_OUTCOME_LABELS, VISIT_OUTCOME_COLORS } from '@/types/canvass';

const { RangePicker } = DatePicker;

// Stacking order: positive first, neutral middle, negative last
const OUTCOME_ORDER: VisitOutcome[] = [
  'SPOKE_WITH',
  'LEFT_LITERATURE',
  'NOT_HOME',
  'COME_BACK_LATER',
  'ALREADY_VOTED',
  'REFUSED',
  'MOVED',
];

export default function CanvassTrendsCard() {
  const { message } = App.useApp();
  const screens = Grid.useBreakpoint();
  const isMobile = !screens.md;

  const [data, setData] = useState<CanvassOutcomeTrendsData | null>(null);
  const [loading, setLoading] = useState(true);
  const [granularity, setGranularity] = useState<'day' | 'week'>('day');
  const [percentMode, setPercentMode] = useState(false);
  const [dateRange, setDateRange] = useState<[dayjs.Dayjs, dayjs.Dayjs]>([
    dayjs().subtract(30, 'day'),
    dayjs(),
  ]);

  useEffect(() => {
    let cancelled = false;
    const fetchTrends = async () => {
      setLoading(true);
      try {
        const res = await api.get('/map/canvass/trends', {
          params: {
            granularity,
            dateFrom: dateRange[0].format('YYYY-MM-DD'),
            dateTo: dateRange[1].format('YYYY-MM-DD'),
          },
        });
        if (!cancelled) setData(res.data);
      } catch {
        if (!cancelled) message.error('Failed to load outcome trends');
      } finally {
        if (!cancelled) setLoading(false);
      }
    };
    fetchTrends();
    return () => { cancelled = true; };
  }, [granularity, dateRange, message]);

  // Transform series for percentage mode
  const chartData = useMemo(() => {
    if (!data?.series?.length) return [];
    if (!percentMode) return data.series;

    return data.series.map((point) => {
      const total = OUTCOME_ORDER.reduce((sum, o) => sum + ((point[o] as number) || 0), 0);
      if (total === 0) return point;
      const pct: Record<string, unknown> = { date: point.date };
      for (const o of OUTCOME_ORDER) {
        pct[o] = Math.round((((point[o] as number) || 0) / total) * 100);
      }
      return pct;
    });
  }, [data, percentMode]);

  // Donut data from totals
  const donutData = useMemo(() => {
    if (!data?.totals) return [];
    return OUTCOME_ORDER
      .filter((o) => (data.totals[o] || 0) > 0)
      .map((o) => ({
        name: VISIT_OUTCOME_LABELS[o],
        value: data.totals[o] || 0,
        color: VISIT_OUTCOME_COLORS[o],
      }));
  }, [data]);

  const totalVisits = useMemo(() => {
    if (!data?.totals) return 0;
    return Object.values(data.totals).reduce((s, v) => s + (v || 0), 0);
  }, [data]);

  const hasData = chartData.length > 0;

  return (
    <Card
      title="Outcome Trends"
      size="small"
      extra={
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
          <Segmented
            size="small"
            options={[
              { label: 'Day', value: 'day' },
              { label: 'Week', value: 'week' },
            ]}
            value={granularity}
            onChange={(v) => setGranularity(v as 'day' | 'week')}
          />
          <Switch
            size="small"
            checkedChildren="%"
            unCheckedChildren="#"
            checked={percentMode}
            onChange={setPercentMode}
          />
          <RangePicker
            size="small"
            value={dateRange}
            onChange={(vals) => {
              if (vals && vals[0] && vals[1]) {
                setDateRange([vals[0], vals[1]]);
              }
            }}
            allowClear={false}
            style={{ width: isMobile ? '100%' : 220 }}
          />
        </div>
      }
    >
      {loading ? (
        <div style={{ textAlign: 'center', padding: 48 }}>
          <Spin />
        </div>
      ) : !hasData ? (
        <Empty description="No visit data for this period" />
      ) : (
        <Row gutter={16}>
          <Col xs={24} md={16}>
            <ResponsiveContainer width="100%" height={200}>
              <AreaChart data={chartData} margin={{ top: 4, right: 8, left: -16, bottom: 0 }}>
                <CartesianGrid strokeDasharray="3 3" strokeOpacity={0.3} />
                <XAxis
                  dataKey="date"
                  tick={{ fontSize: 10 }}
                  interval="preserveStartEnd"
                  tickFormatter={(v: string) =>
                    granularity === 'week'
                      ? dayjs(v).format('MMM D')
                      : dayjs(v).format('M/D')
                  }
                />
                <YAxis
                  tick={{ fontSize: 10 }}
                  tickFormatter={(v: number) => (percentMode ? `${v}%` : String(v))}
                />
                <Tooltip
                  contentStyle={{ fontSize: 12, borderRadius: 6 }}
                  labelFormatter={(v) => dayjs(String(v)).format('ddd, MMM D')}
                  formatter={(value, name) => [
                    percentMode ? `${value}%` : value,
                    VISIT_OUTCOME_LABELS[name as VisitOutcome] || name,
                  ]}
                />
                {OUTCOME_ORDER.map((outcome) => (
                  <Area
                    key={outcome}
                    type="monotone"
                    dataKey={outcome}
                    stackId="1"
                    stroke={VISIT_OUTCOME_COLORS[outcome]}
                    fill={VISIT_OUTCOME_COLORS[outcome]}
                    fillOpacity={0.6}
                  />
                ))}
              </AreaChart>
            </ResponsiveContainer>
          </Col>
          <Col xs={24} md={8}>
            <MiniDonutChart data={donutData} height={140} innerRadius={36} outerRadius={56} />
            <div style={{ marginTop: 8 }}>
              {OUTCOME_ORDER.filter((o) => (data?.totals[o] || 0) > 0).map((o) => {
                const count = data?.totals[o] || 0;
                const pct = totalVisits > 0 ? Math.round((count / totalVisits) * 100) : 0;
                return (
                  <div
                    key={o}
                    style={{
                      display: 'flex',
                      alignItems: 'center',
                      gap: 6,
                      marginBottom: 2,
                      fontSize: 12,
                    }}
                  >
                    <span
                      style={{
                        width: 8,
                        height: 8,
                        borderRadius: '50%',
                        background: VISIT_OUTCOME_COLORS[o],
                        flexShrink: 0,
                      }}
                    />
                    <Typography.Text style={{ flex: 1, fontSize: 12 }} ellipsis>
                      {VISIT_OUTCOME_LABELS[o]}
                    </Typography.Text>
                    <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                      {count} ({pct}%)
                    </Typography.Text>
                  </div>
                );
              })}
            </div>
          </Col>
        </Row>
      )}
    </Card>
  );
}
