import { IconArrowDown, IconArrowUp, IconClose, IconDownload, IconInfoCircle, IconRefresh, IconSearch, IconSetting } from '@douyinfe/semi-icons';
import { Button, Card, Empty, Input, SideSheet, Spin, Switch, Table, Tag } from '@douyinfe/semi-ui';
import { useQuery } from '@tanstack/react-query';
import { type CSSProperties, FormEvent, type KeyboardEvent, memo, type RefObject, useEffect, useMemo, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { api } from '../../api/client';
import type { DailyMileageRow, MileageStatistics, Page, VehicleRow } from '../../api/types';
import { createMileageExportStream, type MileageExportStream } from '../domain/mileageExport';
import { formatZhNumber } from '../domain/formatters';
import { InlineError, PanelEmpty, PanelLoading } from '../shared/AsyncState';
import { MonitorReturnBar } from '../shared/MonitorReturnBar';
import { TablePagination } from '../shared/TablePagination';
import { VehicleCandidateList } from '../shared/VehicleCandidateList';
import { mergeVehicleCandidates } from '../shared/vehicleCandidates';
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
import { WorkspaceMetricRail } from '../shared/WorkspaceMetricRail';
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
import { QUERY_MEMORY, retainPreviousPageWithinScope } from '../queryPolicy';
import { monitorReturnFromParams, preserveMonitorReturn } from '../routing/monitorContext';
import { useMobileLayout } from '../hooks/useMobileLayout';
import { useSideSheetA11y } from '../hooks/useSideSheetA11y';

const DAY = 86_400_000;
const DETAIL_LIMIT = 10_000;
const MAX_SELECTED_VEHICLES = 20;
const PAGE_SIZE = 20;
const EXPORT_VEHICLE_PAGE_SIZE = 2_000;
const EXPORT_VIN_BATCH_SIZE = 50;
const MAX_MILEAGE_RANGE_DAYS = 366;

type VehicleOption = Pick<VehicleRow, 'vin' | 'plate'>;
type MileageProtocol = 'GB32960' | 'JT808' | 'YUTONG_MQTT';
type MileageSourceOption = { protocol: MileageProtocol; label: string; mileageType: string; enabled: boolean };
type Criteria = { vehicles: VehicleOption[]; dateFrom: string; dateTo: string; sources: MileageSourceOption[] };
type ExportProgress = { label: string; completed?: number; total?: number };

const SOURCE_STORAGE_KEY = 'vehicle-platform:mileage-source-strategy';
const DEFAULT_SOURCES: MileageSourceOption[] = [
  { protocol: 'GB32960', label: '国标 GB32960', mileageType: '仪表盘里程', enabled: true },
  { protocol: 'JT808', label: '交通部 JT/T 808', mileageType: 'GPS 里程', enabled: true },
  { protocol: 'YUTONG_MQTT', label: '宇通 MQTT', mileageType: '仪表盘里程', enabled: true }
];

function localDate(value = new Date()) {
  const offset = value.getTimezoneOffset() * 60_000;
  return new Date(value.getTime() - offset).toISOString().slice(0, 10);
}

function defaultWindow(days = 7, endOffsetDays = 0) {
  const end = new Date(Date.now() - endOffsetDays * DAY);
  return { dateFrom: localDate(new Date(end.getTime() - (days - 1) * DAY)), dateTo: localDate(end) };
}

function isSameRange(criteria: Pick<Criteria, 'dateFrom' | 'dateTo'>, range: { dateFrom: string; dateTo: string }) {
  return criteria.dateFrom === range.dateFrom && criteria.dateTo === range.dateTo;
}

function formatKm(value?: number) {
  if (value == null || !Number.isFinite(value)) return '—';
  return formatZhNumber(value, 1);
}

function inclusiveDays(dateFrom: string, dateTo: string) {
  const from = Date.parse(`${dateFrom}T00:00:00Z`);
  const to = Date.parse(`${dateTo}T00:00:00Z`);
  return Number.isFinite(from) && Number.isFinite(to) && to >= from ? Math.round((to - from) / DAY) + 1 : 0;
}

function mileageDateRangeError(criteria: Pick<Criteria, 'dateFrom' | 'dateTo'>) {
  if (!criteria.dateFrom || !criteria.dateTo) return '请选择完整的开始和结束日期';
  const days = inclusiveDays(criteria.dateFrom, criteria.dateTo);
  if (!days) return '结束日期不能早于开始日期';
  if (days > MAX_MILEAGE_RANGE_DAYS) return `单次最多查询 ${MAX_MILEAGE_RANGE_DAYS} 个自然日，请缩小日期范围`;
  return '';
}

function mileageParams(criteria: Criteria, offset = 0) {
  const params = new URLSearchParams({ dateFrom: criteria.dateFrom, dateTo: criteria.dateTo });
  if (criteria.vehicles.length) params.set('vins', criteria.vehicles.map((vehicle) => vehicle.vin).join(','));
  else params.set('vehicleScope', 'bound');
  params.set('protocols', criteria.sources.filter((source) => source.enabled).map((source) => source.protocol).join(','));
  if (offset >= 0) {
    params.set('deduplicate', '1');
    params.set('limit', String(DETAIL_LIMIT));
    params.set('offset', String(offset));
  }
  return params;
}

function initialCriteria(searchParams: URLSearchParams): Criteria {
  const defaults = defaultWindow();
  const vins = (searchParams.get('vins') ?? '').split(',').map((vin) => vin.trim()).filter(Boolean).slice(0, MAX_SELECTED_VEHICLES);
  const requestedProtocols = (searchParams.get('protocols') ?? '').split(',').filter((protocol): protocol is MileageProtocol => DEFAULT_SOURCES.some((source) => source.protocol === protocol));
  let sources = DEFAULT_SOURCES.map((source) => ({ ...source }));
  if (requestedProtocols.length) {
    sources = [...requestedProtocols.map((protocol) => ({ ...DEFAULT_SOURCES.find((source) => source.protocol === protocol)!, enabled: true })), ...DEFAULT_SOURCES.filter((source) => !requestedProtocols.includes(source.protocol)).map((source) => ({ ...source, enabled: false }))];
  } else {
    try {
      const stored = JSON.parse(window.localStorage.getItem(SOURCE_STORAGE_KEY) ?? '[]') as Partial<MileageSourceOption>[];
      const normalized = stored.flatMap((item) => {
        const source = DEFAULT_SOURCES.find((candidate) => candidate.protocol === item.protocol);
        return source ? [{ ...source, enabled: item.enabled !== false }] : [];
      });
      if (normalized.length === DEFAULT_SOURCES.length && normalized.some((source) => source.enabled)) sources = normalized;
    } catch { /* retain safe defaults */ }
  }
  return {
    vehicles: vins.map((vin) => ({ vin, plate: '' })),
    dateFrom: searchParams.get('dateFrom') ?? defaults.dateFrom,
    dateTo: searchParams.get('dateTo') ?? defaults.dateTo,
    sources
  };
}

function SourceStrategy({ value, onChange }: { value: MileageSourceOption[]; onChange: (sources: MileageSourceOption[]) => void }) {
  const [open, setOpen] = useState(false);
  const mobileLayout = useMobileLayout();
  const enabled = value.filter((source) => source.enabled);
  const primarySource = enabled[0];
  useSideSheetA11y(open, '.v2-mileage-source-sidesheet', 'v2-mileage-source-strategy', '数据源策略配置', '关闭数据源策略');
  const update = (sources: MileageSourceOption[]) => {
    onChange(sources);
    try { window.localStorage.setItem(SOURCE_STORAGE_KEY, JSON.stringify(sources)); } catch { /* preference persistence is optional */ }
  };
  const move = (index: number, direction: -1 | 1) => {
    const target = index + direction;
    if (target < 0 || target >= value.length) return;
    const next = [...value];
    [next[index], next[target]] = [next[target], next[index]];
    update(next);
  };
  const toggle = (protocol: MileageProtocol) => {
    const current = value.find((source) => source.protocol === protocol);
    if (current?.enabled && enabled.length === 1) return;
    update(value.map((source) => source.protocol === protocol ? { ...source, enabled: !source.enabled } : source));
  };

  return <div className="v2-mileage-source-strategy">
    <Button className="v2-mileage-source-trigger" theme="light" icon={<IconSetting />} aria-haspopup="dialog" aria-expanded={open} aria-controls="v2-mileage-source-strategy" title={`当前优先：${primarySource?.label ?? '未配置'}`} onClick={() => setOpen((current) => !current)}>
      <span>数据源</span><em>{primarySource?.protocol ?? '未配置'} 优先</em><b>{enabled.length}/3</b>
    </Button>
    <SideSheet
      className="v2-mileage-source-sidesheet"
      visible={open}
      aria-label="数据源策略"
      placement={mobileLayout ? 'bottom' : 'right'}
      width={mobileLayout ? undefined : 430}
      height={mobileLayout ? 'min(58dvh, 500px)' : undefined}
      title={<div className="v2-mileage-source-title"><strong>数据源策略</strong><span>同车同日按优先级选择一个里程来源</span></div>}
      onCancel={() => setOpen(false)}
      footer={<div className="v2-mileage-source-footer"><span>同车同日只使用一个来源，避免重复累计；至少保留一个来源。</span><Button theme="solid" onClick={() => setOpen(false)}>完成</Button></div>}
    >
      <div className="v2-mileage-source-list">{value.map((source, index) => <Card key={source.protocol} className={`v2-mileage-source-card${source.enabled ? '' : ' is-disabled'}`} bodyStyle={{ padding: 0 }}>
        <Switch className="v2-mileage-source-switch" checked={source.enabled} aria-label={`${source.enabled ? '禁用' : '启用'} ${source.label}`} onChange={() => toggle(source.protocol)} />
        <div className="v2-mileage-source-copy"><strong>{source.label}</strong><small><Tag color="blue" type="light" size="small">{source.mileageType}</Tag><code>{source.protocol}</code></small></div>
        <Tag className="v2-mileage-source-priority" color={source.enabled ? 'blue' : 'grey'} type="light" size="small">{source.enabled ? `优先级 ${enabled.findIndex((item) => item.protocol === source.protocol) + 1}` : '已禁用'}</Tag>
        <div className="v2-mileage-source-order"><Button theme="borderless" aria-label={`上移 ${source.label}`} icon={<IconArrowUp />} disabled={index === 0} onClick={() => move(index, -1)} /><Button theme="borderless" aria-label={`下移 ${source.label}`} icon={<IconArrowDown />} disabled={index === value.length - 1} onClick={() => move(index, 1)} /></div>
      </Card>)}</div>
    </SideSheet>
  </div>;
}

function VehicleMultiSelect({ value, onChange }: { value: VehicleOption[]; onChange: (vehicles: VehicleOption[]) => void }) {
  const [search, setSearch] = useState('');
  const [debounced, setDebounced] = useState('');
  const [open, setOpen] = useState(false);
  const closeTimerRef = useRef<number>();
  useEffect(() => { const timer = window.setTimeout(() => setDebounced(search.trim()), 220); return () => window.clearTimeout(timer); }, [search]);
  useEffect(() => () => window.clearTimeout(closeTimerRef.current), []);
  const openPicker = () => {
    window.clearTimeout(closeTimerRef.current);
    setOpen(true);
  };
  const closePicker = () => {
    window.clearTimeout(closeTimerRef.current);
    closeTimerRef.current = window.setTimeout(() => setOpen(false), 120);
  };
  const candidateParams = useMemo(() => {
    const params = new URLSearchParams({ limit: '12', offset: '0' });
    if (debounced) params.set('keyword', debounced);
    return params;
  }, [debounced]);
  const candidates = useQuery({
    queryKey: ['mileage-vehicle-options', candidateParams.toString()],
    queryFn: ({ signal }) => api.vehicles(candidateParams, signal),
    enabled: open,
    staleTime: 30_000,
    gcTime: QUERY_MEMORY.optionGcTime
  });
  const selected = useMemo(() => new Set(value.map((vehicle) => vehicle.vin)), [value]);
  const options = useMemo(() => mergeVehicleCandidates(candidates.data?.items ?? []), [candidates.data?.items]);

  const add = (vehicle: VehicleRow) => {
    if (selected.has(vehicle.vin) || value.length >= MAX_SELECTED_VEHICLES) return;
    onChange([...value, { vin: vehicle.vin, plate: vehicle.plate }]);
    setSearch('');
  };

  return <label className="v2-mileage-vehicle-field">
    <span>车牌</span>
    <div className={`v2-mileage-multiselect${open ? ' is-open' : ''}`}>
      <IconSearch />
      <div className="v2-mileage-selection">
        {value.map((vehicle) => <Tag
          key={vehicle.vin}
          className="v2-mileage-chip"
          color="blue"
          type="light"
          closable
          onClose={(_, event) => {
            event.stopPropagation();
            onChange(value.filter((item) => item.vin !== vehicle.vin));
          }}
        >
          {vehicle.plate || vehicle.vin}
        </Tag>)}
        <Input borderless value={search} onFocus={openPicker} onBlur={closePicker} onChange={(next) => { setSearch(next); setOpen(true); }} placeholder={value.length ? '继续添加车牌' : '输入车牌搜索，可多选'} aria-label="搜索车牌" />
      </div>
      {open ? <VehicleCandidateList
        className="v2-mileage-options"
        items={options}
        loading={candidates.isLoading}
        error={candidates.isError ? (candidates.error instanceof Error ? candidates.error.message : '车牌候选加载失败') : undefined}
        onRetry={() => candidates.refetch()}
        emptyText="没有匹配的车牌"
        selectedVins={selected}
        disableSelected
        header="车牌候选"
        meta={`${value.length}/${MAX_SELECTED_VEHICLES} 已选`}
        showProtocols
        onSelect={add}
      /> : null}
    </div>
    <small>支持车牌关键字搜索，最多选择 {MAX_SELECTED_VEHICLES} 辆</small>
  </label>;
}

function SummaryRail({ data, criteria, fleetTotal, loading }: { data?: MileageStatistics; criteria: Criteria; fleetTotal?: number; loading: boolean }) {
  const days = inclusiveDays(criteria.dateFrom, criteria.dateTo);
  const vehicleCount = criteria.vehicles.length ? data?.vehicleCount ?? 0 : fleetTotal ?? 0;
  const summaryRange = criteria.dateFrom.slice(0, 4) === criteria.dateTo.slice(0, 4)
    ? `${criteria.dateFrom.replace(/-/g, '/')} — ${criteria.dateTo.slice(5).replace('-', '/')}`
    : `${criteria.dateFrom.replace(/-/g, '/')} — ${criteria.dateTo.replace(/-/g, '/')}`;
  const items = loading ? [
    ['已绑定主车辆', '—', '正在按新筛选范围查询'],
    ['统计天数', `${days} 天`, summaryRange],
    ['区间总里程', '—', '正在计算区间汇总'],
    ['日均里程', '—', '正在计算有效车辆日']
  ] : [
    ['已绑定主车辆', `${vehicleCount} 辆`, criteria.vehicles.length ? `已选择 ${criteria.vehicles.length} 辆` : `档案口径 · ${data?.vehicleCount ?? 0} 辆有里程`],
    ['统计天数', `${days} 天`, summaryRange],
    ['区间总里程', `${formatKm(data?.periodMileageKm)} km`, `${data?.recordCount ?? 0} 条车辆日记录`],
    ['日均里程', `${formatKm(data?.averageDailyMileageKm)} km`, '按有效车辆日平均']
  ];
  const primary = items[2];
  const secondary = [items[0], items[1], items[3]];
  return <WorkspaceMetricRail
    className="v2-mileage-summary"
    cardClassName="v2-mileage-summary-card"
    secondaryClassName="v2-mileage-summary-secondary"
    primaryValueClassName="v2-mileage-summary-value"
    ariaLabel="里程查询统计信息"
    primary={{ label: primary[0], value: primary[1], note: primary[2] }}
    secondary={secondary.map(([label, value, note], index) => ({ label, value, note, className: `is-${['fleet', 'range', 'average'][index]}` }))}
  />;
}

type VehicleMileageMatrix = VehicleOption & { days: Map<string, number>; sources: Map<string, string>; totalMileageKm: number };

function rangeDates(dateFrom: string, dateTo: string) {
  const dates: string[] = [];
  const cursor = new Date(`${dateFrom}T00:00:00Z`);
  const end = new Date(`${dateTo}T00:00:00Z`);
  while (cursor <= end && dates.length < MAX_MILEAGE_RANGE_DAYS) {
    dates.push(cursor.toISOString().slice(0, 10));
    cursor.setUTCDate(cursor.getUTCDate() + 1);
  }
  return dates;
}

function dateLabel(date: string) {
  const [, month, day] = date.split('-');
  return `${Number(month)}/${Number(day)}`;
}

function MileageMatrixGuide() {
  return <aside id="v2-mileage-matrix-guide" className="v2-mileage-matrix-guide" role="note" aria-label="里程矩阵读表说明">
    <span className="v2-mileage-matrix-guide-title"><IconInfoCircle /><strong>读表说明</strong></span>
    <span><Tag color="blue" type="light" size="small">0 km</Tag>已上报、无里程增量</span>
    <span><Tag color="grey" type="light" size="small">—</Tag>无可用里程</span>
    <span><Tag color="blue" type="light" size="small">色阶</Tag>颜色越深、里程越高</span>
    <span className="is-mobile-hint">左右滑动查看日期 · 车牌与总里程固定</span>
  </aside>;
}

function scrollMileageMatrixFromKeyboard(event: KeyboardEvent<HTMLDivElement>) {
  if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
  const scroller = event.currentTarget.querySelector<HTMLElement>('.semi-table-body');
  if (!scroller || scroller.scrollWidth <= scroller.clientWidth) return;
  const maximum = scroller.scrollWidth - scroller.clientWidth;
  const next = scroller.scrollLeft + (event.key === 'ArrowRight' ? 96 : -96);
  scroller.scrollLeft = Math.max(0, Math.min(maximum, next));
  event.preventDefault();
}

const MileageTable = memo(function MileageTable({ rows, dates, scrollRef }: { rows: VehicleMileageMatrix[]; dates: string[]; scrollRef: RefObject<HTMLDivElement> }) {
  const { columns, tableWidth } = useMemo(() => {
    let maxDailyMileage = 1;
    for (const row of rows) {
      for (const mileage of row.days.values()) maxDailyMileage = Math.max(maxDailyMileage, mileage);
    }
    return {
      columns: [
        { title: '车牌', dataIndex: 'plate', className: 'is-plate', width: 120, render: (_value: string, row: VehicleMileageMatrix) => <strong>{row.plate || '未绑定'}</strong> },
        ...dates.map((date) => ({
          title: dateLabel(date), dataIndex: date, className: 'is-number is-date', width: 96,
          onHeaderCell: () => ({ title: date, 'aria-label': `${date} 每日里程` }),
          onCell: (row?: VehicleMileageMatrix) => {
            const mileage = row?.days.get(date);
            const source = row?.sources.get(date);
            const intensity = mileage && mileage > 0 ? .035 + mileage / maxDailyMileage * .13 : 0;
            return {
              className: `is-number is-date${mileage != null ? ' is-daily' : ' is-empty'}`,
              title: mileage != null ? `来源：${source || '—'}` : '无可用里程',
              'aria-label': mileage != null ? `${date}，${formatKm(mileage)} 公里，来源 ${source || '未知'}` : `${date}，无可用里程`,
              style: intensity ? { backgroundColor: `rgba(37, 99, 235, ${intensity.toFixed(3)})` } : undefined
            };
          },
          render: (_value: unknown, row: VehicleMileageMatrix) => {
            const mileage = row.days.get(date);
            return mileage != null ? `${formatKm(mileage)} km` : '—';
          }
        })),
        { title: '区间总里程', dataIndex: 'totalMileageKm', className: 'is-number is-total', width: 128, onCell: () => ({ className: 'is-number is-period is-total' }), render: (value: number) => `${formatKm(value)} km` }
      ],
      tableWidth: 120 + dates.length * 96 + 128
    };
  }, [dates, rows]);
  return <div
    className="v2-mileage-table-wrap"
    ref={scrollRef}
    role="region"
    aria-label="车辆每日里程矩阵，可横向滚动查看日期"
    aria-describedby="v2-mileage-matrix-guide"
    tabIndex={0}
    onKeyDown={scrollMileageMatrixFromKeyboard}
    style={{ '--v2-mileage-mobile-table-width': `${96 + dates.length * 78 + 104}px` } as CSSProperties}
  >
      <Table className="v2-mileage-table" columns={columns} dataSource={rows} rowKey="vin" pagination={false} scroll={{ x: Math.max(556, tableWidth) }} />
    </div>;
});

export default function StatisticsPage() {
  const [searchParams, setSearchParams] = useSearchParams();
  const monitorReturn = monitorReturnFromParams(searchParams);
  const [draft, setDraft] = useState<Criteria>(() => initialCriteria(searchParams));
  const [criteria, setCriteria] = useState<Criteria>(() => initialCriteria(searchParams));
  const [page, setPage] = useState(1);
  const [isExporting, setIsExporting] = useState(false);
  const [exportFeedback, setExportFeedback] = useState('');
  const [exportProgress, setExportProgress] = useState<ExportProgress>();
  const [validationError, setValidationError] = useState('');
  const [filtersCollapsed, setFiltersCollapsed] = useState(true);
  const exportControllerRef = useRef<AbortController | null>(null);
  const pageRef = useRef<HTMLDivElement>(null);
  const tableScrollRef = useRef<HTMLDivElement>(null);
  const mountedRef = useRef(true);
  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
      exportControllerRef.current?.abort();
    };
  }, []);
  useEffect(() => {
    const page = pageRef.current;
    if (!page) return;
    const redirectWheelToTable = (event: WheelEvent) => {
      if (window.matchMedia('(max-width: 680px)').matches || event.ctrlKey || event.shiftKey || Math.abs(event.deltaY) <= Math.abs(event.deltaX)) return;
      if (event.target instanceof Element && event.target.closest('input,button,select,textarea,[role="dialog"],[role="listbox"]')) return;
      const scroller = tableScrollRef.current;
      if (!scroller) return;
      const maxScrollTop = Math.max(0, scroller.scrollHeight - scroller.clientHeight);
      const nextScrollTop = Math.max(0, Math.min(maxScrollTop, scroller.scrollTop + event.deltaY));
      if (nextScrollTop === scroller.scrollTop) return;
      scroller.scrollTop = nextScrollTop;
      event.preventDefault();
    };
    page.addEventListener('wheel', redirectWheelToTable, { passive: false });
    return () => page.removeEventListener('wheel', redirectWheelToTable);
  }, []);
  const hasVehicles = criteria.vehicles.length > 0;
  const criteriaError = mileageDateRangeError(criteria);
  const fleetParams = useMemo(() => new URLSearchParams({ limit: String(PAGE_SIZE), offset: String((page - 1) * PAGE_SIZE), bindingStatus: 'bound' }), [page]);
  const fleetVehicles = useQuery({
    queryKey: ['mileage-fleet-page', fleetParams.toString()],
    queryFn: ({ signal }) => api.vehicleCoverage(fleetParams, signal),
    enabled: !hasVehicles,
    staleTime: 60_000,
    gcTime: QUERY_MEMORY.summaryGcTime
  });
  const displayVehicles = useMemo<VehicleOption[]>(() => hasVehicles
    ? criteria.vehicles
    : (fleetVehicles.data?.items ?? []).map((vehicle) => ({ vin: vehicle.vin, plate: vehicle.plate })), [criteria.vehicles, fleetVehicles.data?.items, hasVehicles]);
  const statisticsParams = useMemo(() => mileageParams(criteria, -1), [criteria]);
  const statisticsScope = statisticsParams.toString();
  const rowsCriteria = useMemo(() => ({ ...criteria, vehicles: displayVehicles }), [criteria, displayVehicles]);
  const rowsParams = useMemo(() => mileageParams(rowsCriteria, 0), [rowsCriteria]);
  const statistics = useQuery({ queryKey: ['mileage-statistics', statisticsScope], queryFn: ({ signal }) => api.mileageStatistics(statisticsParams, signal), enabled: !criteriaError, staleTime: 60_000, gcTime: QUERY_MEMORY.summaryGcTime });
  const mileage = useQuery<Page<DailyMileageRow>>({ queryKey: ['daily-mileage-query', statisticsScope, rowsParams.toString()], queryFn: ({ signal }) => api.dailyMileage(rowsParams, signal), enabled: !criteriaError && displayVehicles.length > 0, staleTime: 60_000, gcTime: QUERY_MEMORY.highVolumeGcTime, placeholderData: retainPreviousPageWithinScope<Page<DailyMileageRow>>(statisticsScope, 2) });
  const dates = useMemo(() => criteriaError ? [] : rangeDates(criteria.dateFrom, criteria.dateTo), [criteria.dateFrom, criteria.dateTo, criteriaError]);
  const mileageByVin = useMemo(() => {
    const index = new Map<string, { plate: string; days: Map<string, number>; sources: Map<string, string> }>();
    for (const row of mileage.data?.items ?? []) {
      let entry = index.get(row.vin);
      if (!entry) {
        entry = { plate: row.plate || '', days: new Map(), sources: new Map() };
        index.set(row.vin, entry);
      } else if (!entry.plate && row.plate) entry.plate = row.plate;
      entry.days.set(row.date, row.dailyMileageKm);
      entry.sources.set(row.date, row.source);
    }
    return index;
  }, [mileage.data?.items]);
  const rankingByVin = useMemo(() => new Map((statistics.data?.ranking ?? []).map((row) => [row.vin, row])), [statistics.data?.ranking]);
  const matrixRows = useMemo(() => displayVehicles.map((vehicle) => {
    const daily = mileageByVin.get(vehicle.vin);
    const ranking = rankingByVin.get(vehicle.vin);
    const days = daily?.days ?? new Map<string, number>();
    const sources = daily?.sources ?? new Map<string, string>();
    let dailyTotal = 0;
    for (const value of days.values()) dailyTotal += value;
    return { ...vehicle, plate: vehicle.plate || daily?.plate || ranking?.plate || '', days, sources, totalMileageKm: ranking?.mileageKm ?? dailyTotal };
  }), [displayVehicles, mileageByVin, rankingByVin]);
  const totalVehicles = hasVehicles ? criteria.vehicles.length : fleetVehicles.data?.total ?? 0;
  const totalPages = Math.max(1, Math.ceil(totalVehicles / PAGE_SIZE));
  const submit = (event: FormEvent) => {
    event.preventDefault();
    const error = mileageDateRangeError(draft);
    setValidationError(error);
    if (error) return;
    setPage(1); setExportFeedback(''); setCriteria(draft); setSearchParams(preserveMonitorReturn(mileageParams(draft, -1), monitorReturn), { replace: true }); setFiltersCollapsed(true);
  };
  const setRange = (range: { dateFrom: string; dateTo: string }) => { const next = { ...draft, ...range }; setPage(1); setExportFeedback(''); setValidationError(''); setDraft(next); setCriteria(next); setSearchParams(preserveMonitorReturn(mileageParams(next, -1), monitorReturn), { replace: true }); };
  const todayRange = defaultWindow(1);
  const yesterdayRange = defaultWindow(1, 1);
  const sevenDayRange = defaultWindow(7);
  const thirtyDayRange = defaultWindow(30);
  const ninetyDayRange = defaultWindow(90);
  const refreshing = statistics.isFetching || mileage.isFetching || fleetVehicles.isFetching;
  const resultsLoading = fleetVehicles.isLoading || mileage.isLoading || mileage.isPlaceholderData;
  const exportPercent = exportProgress?.total
    ? Math.min(100, Math.round((exportProgress.completed ?? 0) / exportProgress.total * 100))
    : undefined;

  const exportExcel = async () => {
    if (exportControllerRef.current || !totalVehicles || criteriaError) return;
    const controller = new AbortController();
    exportControllerRef.current = controller;
    const reportProgress = (progress: ExportProgress) => {
      if (mountedRef.current && !controller.signal.aborted) setExportProgress(progress);
    };
    setIsExporting(true);
    setExportFeedback('');
    let exportStream: MileageExportStream | undefined;
    try {
      let vehicles: VehicleOption[] = criteria.vehicles.map((vehicle) => ({ ...vehicle }));
      if (!vehicles.length) {
        vehicles = [];
        let offset = 0;
        reportProgress({ label: '正在读取车辆档案', completed: 0, total: totalVehicles });
        while (offset < totalVehicles) {
          const result = await api.vehicleCoverage(new URLSearchParams({ limit: String(EXPORT_VEHICLE_PAGE_SIZE), offset: String(offset), bindingStatus: 'bound' }), controller.signal);
          vehicles.push(...result.items.map((vehicle) => ({ vin: vehicle.vin, plate: vehicle.plate })));
          reportProgress({ label: '正在读取车辆档案', completed: vehicles.length, total: result.total });
          if (!result.items.length) break;
          offset += result.items.length;
          if (offset >= result.total) break;
        }
      }
      const plateByVin = new Map(vehicles.filter((vehicle) => vehicle.plate).map((vehicle) => [vehicle.vin, vehicle.plate]));
      exportStream = createMileageExportStream({
        dateFrom: criteria.dateFrom,
        dateTo: criteria.dateTo,
        dates,
        sources: criteria.sources.filter((source) => source.enabled),
        exportedAt: new Date()
      }, controller.signal);
      const vehicleBatches = criteria.vehicles.length
        ? Array.from({ length: Math.ceil(vehicles.length / EXPORT_VIN_BATCH_SIZE) }, (_, index) => vehicles.slice(index * EXPORT_VIN_BATCH_SIZE, (index + 1) * EXPORT_VIN_BATCH_SIZE))
        : [[] as VehicleOption[]];
      for (const [batchIndex, vehicleBatch] of vehicleBatches.entries()) {
        let offset = 0;
        const mileageLabel = vehicleBatches.length > 1
          ? `正在读取里程数据（${batchIndex + 1}/${vehicleBatches.length} 批）`
          : '正在读取全部车辆里程';
        reportProgress({ label: mileageLabel });
        while (true) {
          const params = mileageParams({ ...criteria, vehicles: vehicleBatch }, offset);
          const result = await api.dailyMileage(params, controller.signal);
          for (const row of result.items) if (row.plate) plateByVin.set(row.vin, row.plate);
          exportStream.appendRows(result.items);
          offset += result.items.length;
          reportProgress({ label: mileageLabel, completed: offset, total: result.total });
          if (!result.items.length || offset >= result.total) break;
        }
      }
      vehicles = vehicles.map((vehicle) => ({ ...vehicle, plate: vehicle.plate || plateByVin.get(vehicle.vin) || '' }));
      reportProgress({ label: '正在后台生成 Excel 文件' });
      await exportStream.finish(vehicles);
      exportStream = undefined;
      if (mountedRef.current) setExportFeedback(`已导出 ${vehicles.length} 辆车`);
    } catch (error) {
      if (mountedRef.current) {
        setExportFeedback(controller.signal.aborted
          ? '已取消导出'
          : error instanceof Error ? `导出失败：${error.message}` : '导出失败，请稍后重试');
      }
    } finally {
      exportStream?.dispose();
      if (exportControllerRef.current === controller) exportControllerRef.current = null;
      if (mountedRef.current) {
        setIsExporting(false);
        setExportProgress(undefined);
      }
    }
  };

  const cancelExport = () => {
    if (!exportControllerRef.current || exportControllerRef.current.signal.aborted) return;
    setExportProgress({ label: '正在取消导出' });
    exportControllerRef.current.abort();
  };

  return <div className="v2-mileage-page" ref={pageRef}>
    <MonitorReturnBar />
    <div className="v2-mileage-discovery-shell">
      <WorkspaceCommandBar
        className="v2-mileage-command-bar"
        ariaLabel="里程查询工作区"
        title="车辆里程分析"
        description="按自然日对比车辆行驶里程与协议来源"
        status={`${criteria.vehicles.length ? `${criteria.vehicles.length} 辆` : '全部授权车辆'} · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)} 天`}
        statusColor={criteria.vehicles.length ? 'blue' : 'grey'}
        meta={<span>{criteria.sources.find((source) => source.enabled)?.protocol ?? '未配置'} 优先</span>}
      />
      <WorkspaceFilterPanel
        className="v2-mileage-query-panel"
        title="里程范围"
        description="车牌、自然日与里程数据源策略"
        mobileSummary={criteria.vehicles.length ? `已选 ${criteria.vehicles.length} 辆 · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)} 天` : `全部车辆 · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)} 天`}
        expanded={!filtersCollapsed}
        status={`${criteria.vehicles.length ? `${criteria.vehicles.length} 辆` : '全部授权车辆'} · ${inclusiveDays(criteria.dateFrom, criteria.dateTo)} 天`}
        statusColor={criteria.vehicles.length ? 'blue' : 'grey'}
        collapsedLabel="修改"
        onToggle={() => setFiltersCollapsed((value) => !value)}
      >
        <form className={`v2-mileage-filter${filtersCollapsed ? ' is-mobile-collapsed' : ''}`} onSubmit={submit}>
          <VehicleMultiSelect value={draft.vehicles} onChange={(vehicles) => setDraft((current) => ({ ...current, vehicles }))} />
          <label><span>开始日期</span><Input aria-label="开始日期" type="date" value={draft.dateFrom} max={draft.dateTo} onChange={(value) => setDraft((current) => ({ ...current, dateFrom: value }))} /></label>
          <label><span>结束日期</span><Input aria-label="结束日期" type="date" value={draft.dateTo} min={draft.dateFrom} onChange={(value) => setDraft((current) => ({ ...current, dateTo: value }))} /></label>
          <Button className="v2-primary-button" theme="solid" htmlType="submit">查询</Button>
          <SourceStrategy value={draft.sources} onChange={(sources) => setDraft((current) => ({ ...current, sources }))} />
          <div className="v2-mileage-ranges"><span>快捷范围</span><Button theme={isSameRange(draft, todayRange) ? 'solid' : 'light'} onClick={() => setRange(todayRange)}>今天</Button><Button theme={isSameRange(draft, yesterdayRange) ? 'solid' : 'light'} onClick={() => setRange(yesterdayRange)}>昨天</Button><Button theme={isSameRange(draft, sevenDayRange) ? 'solid' : 'light'} onClick={() => setRange(sevenDayRange)}>近 7 天</Button><Button theme={isSameRange(draft, thirtyDayRange) ? 'solid' : 'light'} onClick={() => setRange(thirtyDayRange)}>近 30 天</Button><Button theme={isSameRange(draft, ninetyDayRange) ? 'solid' : 'light'} onClick={() => setRange(ninetyDayRange)}>近 90 天</Button></div>
        </form>
        {validationError || criteriaError ? <p className="v2-mileage-validation" role="alert">{validationError || criteriaError}</p> : null}
        <SummaryRail data={statistics.data} criteria={criteria} fleetTotal={fleetVehicles.data?.total} loading={statistics.isLoading} />
      </WorkspaceFilterPanel>
    </div>
    {statistics.isError || mileage.isError || fleetVehicles.isError ? <InlineError message={(statistics.error ?? mileage.error ?? fleetVehicles.error) instanceof Error ? (statistics.error ?? mileage.error ?? fleetVehicles.error as Error).message : '里程数据加载失败'} onRetry={() => { statistics.refetch(); mileage.refetch(); if (!hasVehicles) fleetVehicles.refetch(); }} /> : null}
    <Card className="v2-mileage-results" bodyStyle={{ padding: 0 }}>
      <WorkspacePanelHeader
        title="车辆每日里程"
        description={`${criteria.dateFrom} 至 ${criteria.dateTo}`}
        meta={<span className="v2-workspace-result-meta"><Tag color="blue" type="light" size="small">{hasVehicles ? `${totalVehicles} 辆` : `${displayVehicles.length} / ${totalVehicles} 辆`}</Tag><span>{dates.length} 个自然日</span></span>}
        actionsClassName="v2-mileage-result-actions"
        actions={<><Button className="is-refresh" theme="borderless" aria-label="刷新里程数据" icon={<IconRefresh />} onClick={() => { statistics.refetch(); mileage.refetch(); if (!hasVehicles) fleetVehicles.refetch(); }} disabled={refreshing}>{refreshing ? '更新中' : '刷新'}</Button><Button theme="light" aria-label={isExporting ? '取消导出' : '导出 Excel'} icon={isExporting ? <IconClose /> : <IconDownload />} onClick={isExporting ? cancelExport : exportExcel} disabled={!totalVehicles || Boolean(criteriaError)}>{isExporting ? '取消导出' : '导出 Excel'}</Button></>}
      />
      {exportProgress ? <div className="v2-mileage-export-progress" role="progressbar" aria-label={exportProgress.label} aria-valuemin={0} aria-valuemax={100} aria-valuenow={exportPercent}>
        <span><strong>{exportProgress.label}</strong><small>{exportPercent == null ? '处理中' : `${exportPercent}%`}</small></span>
        <i className={exportPercent == null ? 'is-indeterminate' : ''}><b style={exportPercent == null ? undefined : { width: `${exportPercent}%` }} /></i>
      </div> : null}
      {!resultsLoading && displayVehicles.length ? <MileageMatrixGuide /> : null}
      {resultsLoading ? <PanelLoading className="v2-mileage-loading" title="正在查询里程" description="新筛选范围返回前不会展示上一范围的数据。" /> : displayVehicles.length ? <MileageTable rows={matrixRows} dates={dates} scrollRef={tableScrollRef} /> : null}
      {!resultsLoading && !displayVehicles.length ? <PanelEmpty className="v2-mileage-empty" title="当前没有可展示的车辆" description="选择车牌或调整车辆授权范围后重试。" /> : null}
      <footer>{!hasVehicles && totalVehicles ? <TablePagination page={page} totalPages={totalPages} info={`共 ${totalVehicles.toLocaleString('zh-CN')} 辆 · 每页 ${PAGE_SIZE} 辆${exportFeedback ? ` · ${exportFeedback}` : ''}`} disabled={fleetVehicles.isFetching} onPageChange={setPage} /> : <span className="v2-table-pagination-info">已选择 {totalVehicles.toLocaleString('zh-CN')} 辆车辆{exportFeedback ? ` · ${exportFeedback}` : ''}</span>}</footer>
    </Card>
    <footer className="v2-mileage-evidence"><span>数据更新时间：{statistics.data?.asOf || '—'}</span><span>来源优先级：{criteria.sources.filter((source) => source.enabled).map((source) => source.protocol).join(' ＞ ')}</span><span>当前筛选复用 1 分钟 · 离开后释放明细</span></footer>
  </div>;
}
