import { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import {
  Card,
  DatePicker,
  Radio,
  Select,
  Space,
  Table,
  Typography,
  message,
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import dayjs, { type Dayjs } from 'dayjs';
import ReactECharts from 'echarts-for-react';
import type { EChartsOption } from 'echarts';
import {
  PROMO_METRIC_EVENT_LABELS,
  type PromoMetricEventItem,
  type PromoMetricEventType,
  type PromoMetricTimelineDto,
} from '@dukang/shared-types';
import { request, type Paginated } from '../../lib/api';
import { fmtTime } from '../../lib/constants';
import { AdminPrimaryLink } from '../../components/AdminPrimaryLink';

type Props = {
  promoId: string;
};

const SERIES = [
  { key: 'scan', name: '扫码进入', color: '#1677ff' },
  { key: 'attribution', name: '归因用户', color: '#52c41a' },
  { key: 'register', name: '扫码注册', color: '#faad14' },
  { key: 'order', name: '订单', color: '#eb2f96' },
] as const;

function buildTimelineQs(promoId: string, range: [Dayjs, Dayjs], granularity: 'day' | 'hour') {
  const qs = new URLSearchParams();
  qs.set('dateFrom', range[0].format('YYYY-MM-DD'));
  qs.set('dateTo', range[1].format('YYYY-MM-DD'));
  qs.set('granularity', granularity);
  return `/admin/promo-codes/${promoId}/metrics/timeline?${qs.toString()}`;
}

function buildEventsQs(
  promoId: string,
  page: number,
  pageSize: number,
  range: [Dayjs, Dayjs],
  eventType?: PromoMetricEventType,
) {
  const qs = new URLSearchParams();
  qs.set('page', String(page));
  qs.set('pageSize', String(pageSize));
  qs.set('dateFrom', range[0].format('YYYY-MM-DD'));
  qs.set('dateTo', range[1].format('YYYY-MM-DD'));
  if (eventType) qs.set('eventType', eventType);
  return `/admin/promo-codes/${promoId}/metrics/events?${qs.toString()}`;
}

function parseEventType(raw: string | null): PromoMetricEventType | undefined {
  if (raw === 'SCAN' || raw === 'ATTRIBUTION' || raw === 'REGISTER' || raw === 'ORDER') return raw;
  return undefined;
}

function EventRefLinks({ row }: { row: PromoMetricEventItem }) {
  const navigate = useNavigate();
  const links = [];
  if (row.orderId) {
    links.push(
      <AdminPrimaryLink
        key="order"
        onClick={() => {
          if (row.orderNo) {
            navigate(`/orders?orderNo=${encodeURIComponent(row.orderNo)}`);
          } else {
            navigate('/orders', { state: { openOrderId: String(row.orderId) } });
          }
        }}
      >
        订单 {row.orderNo || row.orderId}
      </AdminPrimaryLink>,
    );
  }
  if (row.userId) {
    links.push(
      <AdminPrimaryLink
        key="user"
        onClick={() => navigate('/users', { state: { openUserId: String(row.userId) } })}
      >
        用户 {row.userNo || row.userId}
      </AdminPrimaryLink>,
    );
  }
  if (links.length) {
    return <Space size={12}>{links}</Space>;
  }
  if (row.sessionId) return <>会话 {row.sessionId}</>;
  return <>—</>;
}

function formatLocation(row: PromoMetricEventItem): string {
  const parts = [row.ipProvince, row.ipCity].filter(Boolean);
  if (parts.length) return parts.join(' ');
  return '—';
}

export default function PromoCodeMetricsPanel({ promoId }: Props) {
  const [searchParams, setSearchParams] = useSearchParams();
  const urlEventType = parseEventType(searchParams.get('eventType'));
  const [range, setRange] = useState<[Dayjs, Dayjs]>([dayjs().subtract(6, 'day'), dayjs()]);
  const [granularity, setGranularity] = useState<'day' | 'hour'>('day');
  const [timeline, setTimeline] = useState<PromoMetricTimelineDto | null>(null);
  const [timelineLoading, setTimelineLoading] = useState(false);
  const [eventType, setEventType] = useState<PromoMetricEventType | undefined>(urlEventType);
  const [eventsPage, setEventsPage] = useState(1);
  const [events, setEvents] = useState<Paginated<PromoMetricEventItem> | null>(null);
  const [eventsLoading, setEventsLoading] = useState(false);

  useEffect(() => {
    setEventType(urlEventType);
    setEventsPage(1);
    if (urlEventType) {
      window.requestAnimationFrame(() => {
        document.getElementById('promo-metric-events')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      });
    }
  }, [urlEventType]);

  const loadTimeline = useCallback(() => {
    setTimelineLoading(true);
    return request<PromoMetricTimelineDto>(buildTimelineQs(promoId, range, granularity))
      .then(setTimeline)
      .catch((e) => {
        message.error(e instanceof Error ? e.message : '加载趋势失败');
        setTimeline(null);
      })
      .finally(() => setTimelineLoading(false));
  }, [promoId, range, granularity]);

  const loadEvents = useCallback(() => {
    setEventsLoading(true);
    return request<Paginated<PromoMetricEventItem>>(
      buildEventsQs(promoId, eventsPage, 20, range, eventType),
    )
      .then(setEvents)
      .catch((e) => {
        message.error(e instanceof Error ? e.message : '加载事件失败');
        setEvents(null);
      })
      .finally(() => setEventsLoading(false));
  }, [promoId, eventsPage, range, eventType]);

  useEffect(() => {
    void loadTimeline();
  }, [loadTimeline]);

  useEffect(() => {
    void loadEvents();
  }, [loadEvents]);

  const chartOption = useMemo<EChartsOption>(() => {
    const buckets = timeline?.buckets ?? [];
    const xData = buckets.map((b) => b.key);

    return {
      tooltip: { trigger: 'axis' },
      legend: { data: SERIES.map((s) => s.name), bottom: 0 },
      grid: { left: 48, right: 24, top: 24, bottom: 48 },
      xAxis: {
        type: 'category',
        data: xData,
        axisLabel: {
          rotate: granularity === 'hour' ? 45 : 0,
          formatter: (v: string) => (granularity === 'hour' ? v.slice(5, 16) : v.slice(5)),
        },
      },
      yAxis: { type: 'value', minInterval: 1 },
      series: SERIES.map((s) => ({
        name: s.name,
        type: 'line',
        smooth: true,
        data: buckets.map((b) => b[s.key]),
        itemStyle: { color: s.color },
        markPoint: {
          symbol: 'pin',
          symbolSize: 42,
          data: (() => {
            const peak = timeline?.peak[s.key];
            if (!peak || peak.count <= 0) return [];
            return [{ name: '高峰', coord: [peak.key, peak.count], value: peak.count }];
          })(),
        },
      })),
    };
  }, [timeline, granularity]);

  const columns: ColumnsType<PromoMetricEventItem> = [
    {
      title: '时间',
      dataIndex: 'createdAt',
      width: 168,
      render: (v: string) => fmtTime(v),
    },
    {
      title: '类型',
      dataIndex: 'eventType',
      width: 108,
      render: (v: PromoMetricEventType) => PROMO_METRIC_EVENT_LABELS[v],
    },
    {
      title: 'ID',
      key: 'ref',
      render: (_, row) => <EventRefLinks row={row} />,
    },
    {
      title: 'IP',
      dataIndex: 'clientIp',
      width: 128,
      render: (v: string | null) => v ?? '—',
    },
    {
      title: '地点',
      key: 'location',
      width: 120,
      render: (_, row) => formatLocation(row),
    },
  ];

  return (
    <Card
      title="数据趋势"
      style={{ marginTop: 16 }}
      extra={
        <Typography.Text type="secondary" style={{ fontSize: 12 }}>
          仅统计功能上线后的新事件
        </Typography.Text>
      }
    >
      <Space wrap style={{ marginBottom: 16 }}>
        <DatePicker.RangePicker
          value={range}
          onChange={(v) => {
            if (v?.[0] && v[1]) {
              setRange([v[0], v[1]]);
              setEventsPage(1);
            }
          }}
          allowClear={false}
        />
        <Radio.Group
          value={granularity}
          onChange={(e) => setGranularity(e.target.value as 'day' | 'hour')}
          optionType="button"
          buttonStyle="solid"
          options={[
            { label: '按日', value: 'day' },
            { label: '按时', value: 'hour' },
          ]}
        />
      </Space>

      <ReactECharts
        option={chartOption}
        style={{ height: 360 }}
        showLoading={timelineLoading}
        notMerge
      />

      <Typography.Title id="promo-metric-events" level={5} style={{ marginTop: 24, marginBottom: 12 }}>
        事件日志
      </Typography.Title>
      <Space wrap style={{ marginBottom: 12 }}>
        <Select
          allowClear
          placeholder="全部类型"
          style={{ width: 160 }}
          value={eventType}
          onChange={(v) => {
            setEventType(v);
            setEventsPage(1);
            const next = new URLSearchParams(searchParams);
            if (v) next.set('eventType', v);
            else next.delete('eventType');
            setSearchParams(next, { replace: true });
          }}
          options={Object.entries(PROMO_METRIC_EVENT_LABELS).map(([value, label]) => ({
            value,
            label,
          }))}
        />
      </Space>
      <Table
        rowKey="id"
        size="small"
        columns={columns}
        dataSource={events?.items ?? []}
        loading={eventsLoading}
        pagination={{
          current: eventsPage,
          pageSize: events?.pageSize ?? 20,
          total: events?.total ?? 0,
          showSizeChanger: false,
          onChange: (p) => setEventsPage(p),
        }}
      />
    </Card>
  );
}
