/* eslint-disable react/no-unstable-nested-components */
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { api, formatTime, getCustomerAvatar, Table, useMobile, usePaymentContext } from '@blocklet/payment-react';
import type { TCustomer, TPaymentCurrency, TMeterEventExpanded } from '@blocklet/payment-types';
import {
  Box,
  Typography,
  Stack,
  Card,
  Autocomplete,
  TextField,
  Button,
  Popover,
  ToggleButton,
  ToggleButtonGroup,
  Skeleton,
  Avatar,
} from '@mui/material';
import { CalendarTodayOutlined, Add } from '@mui/icons-material';
import { useEffect, useMemo } from 'react';
import { useSetState, useLocalStorageState, useRequest } from 'ahooks';
import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { fromUnitToToken } from '@ocap/util';
import { Link } from 'react-router-dom';
import dayjs from '../../libs/dayjs';
import DateRangePicker from '../date-range-picker';
import { getDefaultRanges } from '../../pages/admin/overview';
import AddUsageDialog from './add-usage-dialog';
import CustomerLink from '../customer/link';

interface MeterEventsListProps {
  meterId: string;
  paymentCurrency: TPaymentCurrency;
}

type SearchProps = {
  pageSize: number;
  page: number;
  customer_id?: string;
  start?: number;
  end?: number;
};

interface TMeterEventStats {
  date: string;
  event_count: number;
  total_value: number;
  timestamp: string;
}

interface EventsState {
  stats: TMeterEventStats[];
  customers: TCustomer[];
  statsLoading: boolean;
  anchorEl: any;
  startDate: Date;
  endDate: Date;
  selectedCustomer: TCustomer | null;
  chartType: 'event_count' | 'total_value';
  addUsageDialog: boolean;
}

const fetchEvents = (
  meterId: string,
  params: SearchProps = {} as SearchProps
): Promise<{ list: TMeterEventExpanded[]; count: number }> => {
  const searchParams = new URLSearchParams();
  searchParams.append('meter_id', meterId);

  // 确保 start 和 end 参数被正确添加
  if (params.page !== undefined) {
    searchParams.append('page', String(params.page));
  }
  if (params.pageSize !== undefined) {
    searchParams.append('pageSize', String(params.pageSize));
  }
  if (params.start !== undefined) {
    searchParams.append('start', String(params.start));
  }
  if (params.end !== undefined) {
    searchParams.append('end', String(params.end));
  }
  if (params.customer_id) {
    searchParams.append('customer_id', params.customer_id);
  }

  return api.get(`/api/meter-events?${searchParams.toString()}`).then((res: any) => res.data);
};

const fetchEventStats = (
  meterId: string,
  start: number,
  end: number,
  customerId?: string,
  granularity?: 'hour' | 'day'
): Promise<{ list: TMeterEventStats[]; count: number }> => {
  const params = new URLSearchParams();
  params.append('meter_id', meterId);
  params.append('start', start.toString());
  params.append('end', end.toString());
  if (customerId) {
    params.append('customer_id', customerId);
  }
  if (granularity) {
    params.append('granularity', granularity);
  }
  return api.get(`/api/meter-events/stats?${params.toString()}`).then((res: any) => res.data);
};

const fetchCustomers = (): Promise<{ list: TCustomer[]; count: number }> => {
  return api.get('/api/customers?limit=100').then((res: any) => res.data);
};

const generateEmptyChartData = (startDate: Date, endDate: Date, granularity: 'hour' | 'day') => {
  const data = [];
  const start = dayjs(startDate);
  const end = dayjs(endDate);
  const now = dayjs();

  if (granularity === 'hour') {
    let current = start.startOf('hour');
    const actualEnd = end.isAfter(now) ? now : end;
    while (current.isBefore(actualEnd) || current.isSame(actualEnd, 'hour')) {
      data.push({
        date: current.format('HH:mm'),
        fullDate: current.format('YYYY-MM-DD HH:mm'),
        timestamp: current.unix().toString(),
        event_count: 0,
        total_value: 0,
      });
      current = current.add(1, 'hour');
    }
  } else {
    let current = start.startOf('day');
    const actualEnd = end.isAfter(now, 'day') ? now.startOf('day') : end;
    while (current.isBefore(actualEnd) || current.isSame(actualEnd, 'day')) {
      data.push({
        date: current.format('MM/DD'),
        fullDate: current.format('YYYY-MM-DD'),
        timestamp: current.unix().toString(),
        event_count: 0,
        total_value: 0,
      });
      current = current.add(1, 'day');
    }
  }

  return data;
};

export default function MeterEventsList({ meterId, paymentCurrency }: MeterEventsListProps) {
  const { t } = useLocaleContext();
  const { isMobile } = useMobile('md');
  const { livemode } = usePaymentContext();
  const maxDate = dayjs().endOf('day').toDate();

  const [search, setSearch] = useLocalStorageState<SearchProps>(`meter-events-${meterId}`, {
    defaultValue: {
      pageSize: 10,
      page: 1,
      start: dayjs().subtract(30, 'day').startOf('day').unix(),
      end: dayjs().endOf('day').unix(),
    },
  });

  const {
    data = {
      list: [],
      count: 0,
    },
    refresh,
    loading,
  } = useRequest(() => fetchEvents(meterId, search), {
    refreshDeps: [search],
  });

  const [state, setState] = useSetState<EventsState>({
    stats: [],
    customers: [],
    statsLoading: false,
    anchorEl: null,
    startDate: dayjs().subtract(30, 'day').startOf('day').toDate(),
    endDate: maxDate,
    selectedCustomer: null,
    chartType: 'event_count',
    addUsageDialog: false,
  });

  const granularity = useMemo(() => {
    const start = dayjs(state.startDate);
    const end = dayjs(state.endDate);
    const diffDays = end.diff(start, 'day');

    // 只有当天（0天差异）使用小时，其他都使用天
    if (diffDays === 0) {
      return 'hour' as const;
    }
    return 'day' as const;
  }, [state.startDate, state.endDate]);

  const chartData = useMemo(() => {
    if (state.statsLoading) {
      return [];
    }

    const emptyData = generateEmptyChartData(state.startDate, state.endDate, granularity);

    if (!state.stats.length) {
      return emptyData;
    }

    const dataMap = new Map();
    state.stats.forEach((item) => {
      let key;
      let fullDate;
      if (granularity === 'hour') {
        key = dayjs(item.timestamp).format('HH:mm');
        fullDate = dayjs(item.timestamp).format('YYYY-MM-DD HH:mm');
      } else {
        key = dayjs(item.timestamp).format('MM/DD');
        fullDate = dayjs(item.timestamp).format('YYYY-MM-DD');
      }

      dataMap.set(key, {
        ...item,
        date: key,
        fullDate,
      });
    });

    return emptyData.map((empty) => dataMap.get(empty.date) || empty);
  }, [state.stats, state.statsLoading, state.startDate, state.endDate, granularity]);

  const loadStats = async () => {
    setState({ statsLoading: true });
    try {
      const result = await fetchEventStats(
        meterId,
        dayjs(state.startDate).unix(),
        dayjs(state.endDate).unix(),
        state.selectedCustomer?.id,
        granularity
      );
      setState({ stats: result.list, statsLoading: false });
    } catch (err) {
      console.error('Failed to fetch stats:', err);
      setState({ statsLoading: false });
    }
  };

  const loadCustomers = async () => {
    try {
      const result = await fetchCustomers();
      setState({ customers: result.list });

      // Initialize selected customer if exists in search
      if (search!.customer_id && result.list.length > 0) {
        const selectedCustomer = result.list.find((c) => c.id === search!.customer_id);
        if (selectedCustomer) {
          setState({ selectedCustomer });
        }
      }
    } catch (err) {
      console.error('Failed to fetch customers:', err);
    }
  };

  useEffect(() => {
    loadCustomers();
  }, [meterId]);

  // Initialize state dates from search params
  useEffect(() => {
    if (search?.start && search?.end) {
      setState({
        startDate: dayjs.unix(search.start).toDate(),
        endDate: dayjs.unix(search.end).toDate(),
      });
    }
  }, [search?.start, search?.end]);

  useEffect(() => {
    loadStats();
  }, [state.startDate, state.endDate, state.selectedCustomer, granularity]);

  const onTableChange = ({ page, rowsPerPage }: any) => {
    if (search!.pageSize !== rowsPerPage) {
      setSearch((x) => ({ ...x!, pageSize: rowsPerPage, page: 1 }));
    } else if (search!.page !== page + 1) {
      setSearch((x) => ({ ...x!, page: page + 1 }));
    }
  };

  const onTogglePicker = (e: any) => {
    if (state.anchorEl) {
      setState({ anchorEl: null });
    } else {
      setState({ anchorEl: e.currentTarget });
    }
  };

  const onRangeChange = (range: any) => {
    const newStart = dayjs(range.startDate).startOf('day').unix();
    const newEnd = dayjs(range.endDate).endOf('day').unix();

    setSearch((x) => ({ ...x!, start: newStart, end: newEnd, page: 1 }));
    setState({
      startDate: range.startDate,
      endDate: dayjs(range.endDate).endOf('day').toDate(),
      anchorEl: null,
    });
  };

  const handleChartTypeChange = (_: any, newType: 'event_count' | 'total_value') => {
    if (newType !== null) {
      setState({ chartType: newType });
    }
  };

  const handleCustomerChange = (customer: TCustomer | null) => {
    setSearch((x) => ({ ...x!, customer_id: customer?.id, page: 1 }));
    setState({ selectedCustomer: customer });
  };

  const getCustomerDisplayName = (customer: TCustomer) => {
    return customer.name || customer.email || customer.did || customer.id;
  };

  const handleAddUsage = () => {
    setState({ addUsageDialog: true });
  };

  const handleCloseAddUsage = () => {
    setState({ addUsageDialog: false });
  };

  const handleAddUsageSuccess = () => {
    refresh();
    loadStats();
  };

  const open = Boolean(state.anchorEl);
  const id = open ? 'date-range-picker-popover' : undefined;

  const columns = [
    {
      label: t('admin.meter.events.value'),
      name: 'value',
      options: {
        filter: false,
        sort: false,
        customBodyRenderLite: (_: string, index: number) => {
          const item = data.list[index];
          if (!item) return null;
          const value = fromUnitToToken(item.payload.value || '0', paymentCurrency.decimal);
          return <Link to={`/admin/billing/${item.id}`}>{`${value} ${paymentCurrency.symbol}`}</Link>;
        },
      },
    },
    {
      label: t('admin.meter.events.customer'),
      name: 'customer',
      options: {
        filter: false,
        sort: false,
        customBodyRenderLite: (_: string, index: number) => {
          const item = data.list[index];
          if (!item || !item?.customer) return '-';
          return <CustomerLink customer={item.customer} size="small" />;
        },
      },
    },
    {
      label: t('admin.meter.events.subscription'),
      name: 'subscription',
      options: {
        filter: false,
        sort: false,
        customBodyRenderLite: (_: string, index: number) => {
          const item = data.list[index];
          if (!item) return '-';
          const subscriptionId = (item as any).payload?.subscription_id;
          if (!subscriptionId) return '-';
          return (
            <Link to={`/admin/billing/${subscriptionId}`}>
              <Typography variant="body2" sx={{ color: 'text.link' }}>
                {item?.subscription?.description || subscriptionId}
              </Typography>
            </Link>
          );
        },
      },
    },
    {
      label: t('admin.meter.events.reportTime'),
      name: 'created_at',
      options: {
        filter: false,
        sort: false,
        customBodyRenderLite: (_: string, index: number) => {
          const item = data.list[index];
          return <Link to={`/admin/billing/${item?.id}`}>{item ? formatTime(item.created_at) : '-'}</Link>;
        },
      },
    },
  ];

  return (
    <Box>
      {/* 过滤条件 - 移动端优化 */}
      <Box
        sx={{
          mb: 3,
        }}>
        <Stack
          direction={isMobile ? 'column' : 'row'}
          spacing={2}
          sx={{
            alignItems: isMobile ? 'stretch' : 'center',
            flexWrap: 'wrap',
          }}>
          <Button
            variant="outlined"
            startIcon={<CalendarTodayOutlined />}
            onClick={onTogglePicker}
            size="large"
            sx={{
              minWidth: isMobile ? '100%' : 200,
              justifyContent: isMobile ? 'flex-start' : 'center',
              color: 'text.secondary',
              borderColor: 'grey.300',
              '&:hover': {
                borderColor: 'primary.main',
              },
              backgroundColor: 'grey.50',
            }}>
            {dayjs(state.startDate).format('YYYY-MM-DD')} - {dayjs(state.endDate).format('YYYY-MM-DD')}
          </Button>

          <Autocomplete
            options={state.customers}
            getOptionLabel={getCustomerDisplayName}
            value={state.selectedCustomer}
            onChange={(_, customer) => handleCustomerChange(customer)}
            sx={{
              minWidth: isMobile ? '100%' : 200,
              flex: isMobile ? 1 : 'none',
            }}
            renderInput={(params) => (
              <TextField {...params} label={t('admin.meter.events.filterByCustomer')} size="small" />
            )}
            renderOption={(props, option) => (
              <Box component="li" {...props} sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
                <Avatar
                  src={getCustomerAvatar(
                    option.did,
                    option?.updated_at ? new Date(option.updated_at).toISOString() : undefined,
                    24
                  )}
                  sx={{
                    width: 24,
                    height: 24,
                  }}
                  alt={getCustomerDisplayName(option)}
                />
                {getCustomerDisplayName(option)}
              </Box>
            )}
          />

          {!livemode && (
            <Button
              variant="outlined"
              startIcon={<Add />}
              onClick={handleAddUsage}
              sx={{
                minWidth: isMobile ? '100%' : 'auto',
                color: 'text.link',
              }}>
              {t('admin.meterEvent.add.button')}
            </Button>
          )}
        </Stack>

        {/* 图表类型切换 - 移动端优化 */}
        <Box
          sx={{
            mt: 2,
            display: 'flex',
            justifyContent: isMobile ? 'center' : 'flex-end',
          }}>
          <ToggleButtonGroup
            value={state.chartType}
            exclusive
            onChange={handleChartTypeChange}
            size="small"
            sx={{
              width: isMobile ? '100%' : 'auto',
              '& .MuiToggleButton-root': {
                flex: isMobile ? 1 : 'none',
              },
            }}>
            <ToggleButton value="event_count">{t('admin.meter.events.eventCount')}</ToggleButton>
            <ToggleButton value="total_value">{t('admin.meter.events.totalValue')}</ToggleButton>
          </ToggleButtonGroup>
        </Box>
      </Box>
      {/* 图表 */}
      <Card sx={{ mb: 3 }}>
        <Box
          sx={{
            height: isMobile ? 250 : 300,
            position: 'relative',
            pr: isMobile ? 1 : 2,
            pl: isMobile ? 0.5 : 1,
          }}>
          {state.statsLoading ? (
            <Box sx={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
              <Skeleton variant="rectangular" width="100%" height="100%" />
            </Box>
          ) : (
            <ResponsiveContainer width="100%" height="100%">
              <AreaChart
                data={chartData}
                margin={{
                  top: 10,
                  right: isMobile ? 10 : 30,
                  left: isMobile ? 5 : 10,
                  bottom: (() => {
                    if (granularity === 'hour') {
                      return isMobile ? 50 : 60;
                    }
                    return isMobile ? 30 : 40;
                  })(),
                }}>
                <CartesianGrid strokeDasharray="3 3" />
                <XAxis
                  dataKey="date"
                  tick={{ fontSize: isMobile ? 10 : 11 }}
                  angle={granularity === 'hour' ? -45 : 0}
                  textAnchor={granularity === 'hour' ? 'end' : 'middle'}
                  height={(() => {
                    if (granularity === 'hour') {
                      return isMobile ? 50 : 60;
                    }
                    return isMobile ? 30 : 40;
                  })()}
                  interval={(() => {
                    const dataLength = chartData.length;
                    if (isMobile) {
                      // 移动端：根据数据量智能调整
                      if (dataLength > 20) return Math.floor(dataLength / 6);
                      if (dataLength > 10) return Math.floor(dataLength / 4);
                      if (dataLength > 5) return 1;
                      return 0;
                    }
                    // 桌面端：根据数据量和粒度调整
                    if (granularity === 'hour') {
                      if (dataLength > 24) return Math.floor(dataLength / 12);
                      if (dataLength > 12) return 1;
                      return 0;
                    }
                    if (dataLength > 30) return Math.floor(dataLength / 15);
                    if (dataLength > 15) return 1;
                    return 0;
                  })()}
                />
                <YAxis
                  tick={{ fontSize: isMobile ? 9 : 11 }}
                  width={isMobile ? 35 : 40}
                  tickFormatter={(value) => {
                    // 在移动端简化数字显示
                    if (isMobile && value >= 1000) {
                      return `${(value / 1000).toFixed(1)}k`;
                    }
                    return value.toString();
                  }}
                />
                <Tooltip
                  labelFormatter={(label: any) => {
                    const dataItem = chartData.find((item) => item.date === label);
                    return dataItem?.fullDate || label;
                  }}
                  formatter={(value: any, name: any) => [
                    name === 'event_count' ? value : fromUnitToToken(value, paymentCurrency.decimal),
                    name === 'event_count' ? t('admin.meter.events.eventCount') : t('admin.meter.events.totalValue'),
                  ]}
                  contentStyle={{
                    fontSize: isMobile ? '12px' : '14px',
                    padding: isMobile ? '8px' : '10px',
                  }}
                />
                <Area
                  type="monotone"
                  dataKey={state.chartType}
                  stroke={state.chartType === 'event_count' ? '#8884d8' : '#82ca9d'}
                  fill={state.chartType === 'event_count' ? '#8884d8' : '#82ca9d'}
                  fillOpacity={0.6}
                  strokeWidth={isMobile ? 1.5 : 2}
                />
              </AreaChart>
            </ResponsiveContainer>
          )}
        </Box>
      </Card>
      <Box
        sx={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          mb: 2,
        }}>
        <Typography
          variant="body2"
          sx={{
            color: 'text.secondary',
          }}>
          {t('admin.meter.events.count', { count: data.count })}
        </Typography>
      </Box>
      <Table
        data={data.list}
        columns={columns}
        onChange={onTableChange}
        options={{
          count: data.count,
          page: search!.page - 1,
          rowsPerPage: search!.pageSize,
          responsive: isMobile ? 'vertical' : 'standard',
        }}
        loading={loading}
        emptyNodeText={t('admin.meter.events.empty')}
      />
      {/* 日期选择器弹窗 */}
      <Popover
        id={id}
        open={open}
        anchorEl={state.anchorEl}
        onClose={() => setState({ anchorEl: null })}
        anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}>
        <DateRangePicker
          open
          toggle={onTogglePicker as any}
          maxDate={maxDate}
          definedRanges={getDefaultRanges(maxDate.toISOString())}
          onChange={onRangeChange}
        />
      </Popover>
      {/* 手动添加用量对话框 */}
      <AddUsageDialog
        open={state.addUsageDialog}
        onClose={handleCloseAddUsage}
        meterId={meterId}
        customers={state.customers}
        paymentCurrency={paymentCurrency}
        onSuccess={handleAddUsageSuccess}
      />
    </Box>
  );
}
