import {
  IconChevronLeft, IconChevronRight, IconClose, IconFilter, IconList, IconMapPin,
  IconQrCode, IconRefresh, IconSearch
} from '@douyinfe/semi-icons';
import { Button, Card, Empty, Input, Modal, Select, Spin, Table, Tag, TextArea } from '@douyinfe/semi-ui';
import { useQuery } from '@tanstack/react-query';
import { memo, useCallback, useDeferredValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { Link, useSearchParams } from 'react-router-dom';
import { api } from '../../api/client';
import type { Page, VehicleRealtimeRow } from '../../api/types';
import { FleetMap } from '../map/FleetMap';
import { EmptyState, InlineError } from '../shared/AsyncState';
import { SegmentedTabs } from '../shared/SegmentedTabs';
import { TablePagination } from '../shared/TablePagination';
import { VehicleSourceEvidencePanel } from '../shared/VehicleSourceEvidencePanel';
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
import { formatNumber, relativeFreshness, statusLabel, vehicleStatus } from '../domain/monitor';
import { formatTelemetryValue } from '../domain/telemetry';
import { useMobileLayout } from '../hooks/useMobileLayout';
import { MAX_MONITOR_SEARCH_TERMS, MONITOR_REFRESH, monitorFilterScope, monitorQueryParams, parseMonitorSearchTerms, useMonitorData, useMonitorVehicleCard, type MonitorViewport } from '../hooks/useMonitorData';
import { LIVE_QUERY_POLICY, QUERY_MEMORY, retainPreviousPageWithinScope } from '../queryPolicy';
import { buildMonitorPath, parseMonitorRouteContext, withMonitorReturn } from '../routing/monitorContext';

const protocols = ['', 'GB32960', 'JT808', 'YUTONG_MQTT'];
const statuses = ['', 'online', 'offline', 'driving', 'idle', 'no_location'];
const EMPTY_VEHICLES: VehicleRealtimeRow[] = [];
const MONITOR_VIEW_ITEMS = [
  { key: 'map', label: '地图', icon: <IconMapPin aria-hidden="true" /> },
  { key: 'list', label: '列表', icon: <IconList aria-hidden="true" /> }
] as const;

function BatchVehicleSearchDialog({ initialValue, onApply, onClose }: { initialValue: string; onApply: (value: string) => void; onClose: () => void }) {
  const [draft, setDraft] = useState(initialValue);
  const terms = useMemo(() => parseMonitorSearchTerms(draft), [draft]);

  return <Modal
    className="v2-batch-search-modal"
    visible
    centered
    closeOnEsc
    maskClosable
    width={520}
    title={<div className="v2-batch-search-title"><strong id="batch-search-title">批量搜索车辆</strong><span>从 Excel、文本或聊天记录中直接粘贴车牌</span></div>}
    onCancel={onClose}
    footer={<div className="v2-batch-search-actions"><Button onClick={onClose}>取消</Button><Button theme="solid" disabled={!terms.length} onClick={() => onApply(terms.join('，'))}>应用搜索（{terms.length}）</Button></div>}
  >
    <div className="v2-batch-search-dialog">
      <label htmlFor="batch-vehicle-search">每行一个车牌，也支持空格、逗号或分号分隔</label>
      <TextArea id="batch-vehicle-search" autoFocus value={draft} onChange={setDraft} autosize={{ minRows: 8, maxRows: 14 }} resize="vertical" placeholder={'粤A12345\n粤B67890\n粤C24680'} />
      <div className="v2-batch-search-summary"><span>已识别 <strong>{terms.length}</strong> 辆，重复项已自动去除</span><em>最多 {MAX_MONITOR_SEARCH_TERMS} 辆</em></div>
    </div>
  </Modal>;
}

type AddressCoordinate = { longitude: number; latitude: number; key: string };

function hasRealtimeLocation(vehicle: VehicleRealtimeRow) {
  if (vehicle.locationAvailable != null) return vehicle.locationAvailable;
  return Number.isFinite(vehicle.longitude) && Number.isFinite(vehicle.latitude)
    && Math.abs(vehicle.longitude) <= 180 && Math.abs(vehicle.latitude) <= 90
    && (vehicle.longitude !== 0 || vehicle.latitude !== 0);
}

function hasRealtimeSpeed(vehicle: VehicleRealtimeRow) {
  return vehicle.speedAvailable ?? hasRealtimeLocation(vehicle);
}

function hasRealtimeMileage(vehicle: VehicleRealtimeRow) {
  return vehicle.mileageAvailable ?? hasRealtimeLocation(vehicle);
}

function hasTodayMileage(vehicle: VehicleRealtimeRow): vehicle is VehicleRealtimeRow & { todayMileageKm: number } {
  return vehicle.todayMileageAvailable === true && vehicle.todayMileageKm != null;
}

function hasRealtimeSOC(vehicle: VehicleRealtimeRow) {
  return vehicle.socAvailable ?? (vehicle.primaryProtocol === 'GB32960' || vehicle.primaryProtocol === 'YUTONG_MQTT');
}

function addressCoordinate(vehicle: VehicleRealtimeRow): AddressCoordinate | undefined {
  if (!hasRealtimeLocation(vehicle) || !Number.isFinite(vehicle.longitude) || !Number.isFinite(vehicle.latitude)
    || Math.abs(vehicle.longitude) > 180 || Math.abs(vehicle.latitude) > 90
    || (vehicle.longitude === 0 && vehicle.latitude === 0)) return undefined;
  const longitude = Number(vehicle.longitude.toFixed(4));
  const latitude = Number(vehicle.latitude.toFixed(4));
  return { longitude, latitude, key: `${longitude.toFixed(4)},${latitude.toFixed(4)}` };
}

const MonitorAddressCell = memo(function MonitorAddressCell({ vehicle }: { vehicle: VehicleRealtimeRow }) {
  const current = addressCoordinate(vehicle);
  const [requested, setRequested] = useState<AddressCoordinate>();
  const addressQuery = useQuery({
    queryKey: ['monitor', 'list-address', requested?.key],
    queryFn: ({ signal }) => api.reverseGeocode(new URLSearchParams({
      longitude: requested!.longitude.toFixed(4),
      latitude: requested!.latitude.toFixed(4)
    }), signal),
    enabled: Boolean(requested),
    staleTime: 6 * 60 * 60_000,
    gcTime: QUERY_MEMORY.highVolumeGcTime,
    refetchOnWindowFocus: false,
    retry: 1
  });
  const moved = Boolean(current && requested && current.key !== requested.key);

  if (!current) return <span className="v2-monitor-address-empty">暂无实时位置</span>;
  if (!requested) return <Button className="v2-monitor-address-action" size="small" theme="light" type="primary" icon={<IconMapPin />} aria-label={`解析${vehicle.plate || vehicle.vin}位置`} title="按需调用高德地址解析，不随实时数据刷新" onClick={() => setRequested(current)}>解析位置</Button>;
  if (addressQuery.isFetching && !addressQuery.data) return <span className="v2-monitor-address-loading"><Spin size="small" />解析中</span>;
  if (addressQuery.isError) return <Button className="v2-monitor-address-action is-error" size="small" theme="light" type="danger" aria-label={`${vehicle.plate || vehicle.vin}位置解析失败，重试`} onClick={() => void addressQuery.refetch()}>解析失败，重试</Button>;
  return <div className="v2-monitor-address-result"><span title={addressQuery.data?.formattedAddress}>{addressQuery.data?.formattedAddress || '暂无地址'}</span><small>{addressQuery.dataUpdatedAt ? `解析于 ${new Date(addressQuery.dataUpdatedAt).toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit' })}` : ''}</small>{moved ? <Button className="v2-monitor-address-update" size="small" theme="borderless" type="warning" title="车辆已移动，按需更新地址" onClick={() => setRequested(current)}>位置已移动 · 更新</Button> : null}</div>;
});

function MonitorVehicleTable({ rows, total, page, totalPages, limit, loading, mobile, onSelect, onPage, onLimit }: { rows: VehicleRealtimeRow[]; total: number; page: number; totalPages: number; limit: number; loading: boolean; mobile: boolean; onSelect: (vin: string) => void; onPage: (page: number) => void; onLimit: (limit: number) => void }) {
  const columns = useMemo(() => [
    { title: '车辆', dataIndex: 'plate', width: 210, className: 'v2-monitor-table-vehicle', render: (_value: string, row: VehicleRealtimeRow) => <Button className="v2-monitor-vehicle-action" theme="borderless" type="tertiary" title="在地图中定位" onClick={() => onSelect(row.vin)}><strong>{row.plate || '未绑定车牌'}</strong><span>{row.vin}</span></Button> },
    { title: '速度', dataIndex: 'speedKmh', width: 120, render: (_value: number, row: VehicleRealtimeRow) => <><strong className="v2-monitor-live-value">{hasRealtimeSpeed(row) ? formatNumber(row.speedKmh, 1) : '—'}</strong>{hasRealtimeSpeed(row) ? <small className="v2-monitor-live-unit">km/h</small> : null}</> },
    { title: '当日里程', dataIndex: 'todayMileageKm', width: 140, render: (_value: number, row: VehicleRealtimeRow) => <><strong className="v2-monitor-live-value is-today">{hasTodayMileage(row) ? formatNumber(row.todayMileageKm, 1) : '—'}</strong>{hasTodayMileage(row) ? <small className="v2-monitor-live-unit">km</small> : null}</> },
    { title: '总里程', dataIndex: 'totalMileageKm', width: 170, render: (_value: number, row: VehicleRealtimeRow) => <><strong className="v2-monitor-live-value">{hasRealtimeMileage(row) ? formatNumber(row.totalMileageKm, 1) : '—'}</strong>{hasRealtimeMileage(row) ? <small className="v2-monitor-live-unit">km</small> : null}</> },
    { title: '协议来源', dataIndex: 'primaryProtocol', width: 150, render: (_value: string, row: VehicleRealtimeRow) => <div className="v2-monitor-protocol"><Tag color={row.primaryProtocol ? 'blue' : 'grey'} type="light" size="small">{row.primaryProtocol || '未知'}</Tag>{row.protocols.length > 1 ? <small>+{row.protocols.length - 1} 路</small> : null}</div> },
    { title: '经纬度', dataIndex: 'longitude', width: 190, render: (_value: number, row: VehicleRealtimeRow) => hasRealtimeLocation(row) ? <code className="v2-monitor-coordinate">{row.longitude.toFixed(6)}<br />{row.latitude.toFixed(6)}</code> : <span className="v2-monitor-unavailable">—</span> },
    { title: '地理位置', dataIndex: 'vin', render: (_value: string, row: VehicleRealtimeRow) => <MonitorAddressCell vehicle={row} /> }
  ], [onSelect]);
  return <Card className="v2-monitor-table-panel" bodyStyle={{ padding: 0 }}>
    <WorkspacePanelHeader
      title="车辆实时列表"
      description="覆盖全部授权车辆；缺失值显示“—”，地址按需解析"
      meta={`${total.toLocaleString('zh-CN')} 辆车辆`}
    />
    {!mobile ? <div className="v2-monitor-table-scroll"><Table className="v2-monitor-table" columns={columns} dataSource={rows} rowKey="vin" pagination={false} empty={null} />{loading ? <div className="v2-monitor-table-loading" role="status"><Spin size="small" tip="正在更新车辆实时数据…" /></div> : null}{!loading && !rows.length ? <Empty className="v2-monitor-table-empty" title="暂无符合条件的车辆" description="调整搜索、协议或在线状态筛选后重试。" /> : null}</div> : null}
    {mobile ? <div className="v2-monitor-mobile-cards">{rows.map((row) => <Card className="v2-monitor-mobile-card" key={row.vin}>
      <header><div><strong>{row.plate || '未绑定车牌'}</strong><span>{row.vin}</span></div><div className="v2-monitor-card-heading-actions"><b>{hasRealtimeSpeed(row) ? formatNumber(row.speedKmh, 1) : '—'}{hasRealtimeSpeed(row) ? <small>km/h</small> : null}</b><Button className="v2-monitor-card-locate" size="small" theme="light" type="primary" icon={<IconMapPin />} aria-label={`在地图中定位${row.plate || row.vin}`} onClick={() => onSelect(row.vin)}>地图</Button></div></header>
      <dl><div><dt>当日里程</dt><dd className="is-today">{hasTodayMileage(row) ? `${formatNumber(row.todayMileageKm, 1)} km` : '—'}</dd></div><div><dt>总里程</dt><dd>{hasRealtimeMileage(row) ? `${formatNumber(row.totalMileageKm, 1)} km` : '—'}</dd></div><div><dt>协议来源</dt><dd><span className="v2-monitor-mobile-protocol">{row.primaryProtocol || '未知'}{row.protocols.length > 1 ? ` · ${row.protocols.length} 路` : ''}</span></dd></div><div><dt>经纬度</dt><dd>{hasRealtimeLocation(row) ? <code>{row.longitude.toFixed(6)}, {row.latitude.toFixed(6)}</code> : '—'}</dd></div><div className="is-address"><dt>地理位置</dt><dd><MonitorAddressCell vehicle={row} /></dd></div></dl>
    </Card>)}{loading ? <div className="v2-monitor-table-loading" role="status"><Spin size="small" tip="正在更新车辆实时数据…" /></div> : null}{!loading && !rows.length ? <Empty className="v2-monitor-table-empty" title="暂无符合条件的车辆" description="调整搜索、协议或在线状态筛选后重试。" /> : null}</div> : null}
    <footer><TablePagination page={page} totalPages={totalPages} info={`共 ${total.toLocaleString('zh-CN')} 辆车辆`} onPageChange={onPage} pageSize={limit} pageSizeLabel="每页车辆数" onPageSizeChange={onLimit} pageSizeOptions={[{ value: 20, label: '20 辆/页' }, { value: 50, label: '50 辆/页' }, { value: 100, label: '100 辆/页' }]} /></footer>
  </Card>;
}

function MobileEntry({ onClose }: { onClose: () => void }) {
  const [qr, setQr] = useState('');
  const [error, setError] = useState('');
  const [copyState, setCopyState] = useState<'idle' | 'copied' | 'error'>('idle');
  const [attempt, setAttempt] = useState(0);
  const url = `${window.location.origin}/monitor`;
  useLayoutEffect(() => {
    document.querySelector('.v2-monitor-qr-modal .semi-modal-close')?.setAttribute('aria-label', '关闭手机端入口');
  }, []);
  useEffect(() => {
    if (copyState === 'idle') return;
    const timer = window.setTimeout(() => setCopyState('idle'), 1_800);
    return () => window.clearTimeout(timer);
  }, [copyState]);
  useEffect(() => {
    let cancelled = false;
    setQr('');
    setError('');
    void import('qrcode')
      .then(({ default: QRCode }) => QRCode.toDataURL(url, { width: 240, margin: 2, color: { dark: '#122033', light: '#ffffff' } }))
      .then((value) => { if (!cancelled) setQr(value); })
      .catch(() => { if (!cancelled) setError('二维码生成失败，请检查浏览器环境后重试'); });
    return () => { cancelled = true; };
  }, [attempt, url]);
  const copyURL = async () => {
    try {
      if (!navigator.clipboard?.writeText) throw new Error('clipboard unavailable');
      await navigator.clipboard.writeText(url);
      setCopyState('copied');
    } catch {
      setCopyState('error');
    }
  };
  return <Modal
    className="v2-monitor-qr-modal"
    visible
    centered
    width={390}
    title="手机端全局监控"
    closeIcon={<IconClose aria-label="关闭手机端入口" />}
    closeOnEsc
    maskClosable
    onCancel={onClose}
    footer={<Button block theme="solid" aria-live="polite" onClick={() => void copyURL()}>{copyState === 'copied' ? '已复制访问地址' : copyState === 'error' ? '复制失败，重试' : '复制访问地址'}</Button>}
  >
    <div className="v2-monitor-qr-content">
      <span className="v2-monitor-qr-icon"><IconQrCode /></span>
      <p>扫码后使用现有账号鉴权，不在二维码中保存 Token</p>
      {qr ? <img src={qr} alt="全局监控手机端二维码" /> : error ? <div className="v2-monitor-qr-error" role="alert"><span>{error}</span><Button theme="light" type="danger" onClick={() => setAttempt((value) => value + 1)}>重新生成</Button></div> : <span className="v2-spinner" role="status" aria-label="正在生成二维码" />}
      <code>{url}</code>
    </div>
  </Modal>;
}

const VehicleRow = memo(function VehicleRow({ vehicle, selected, onSelect }: { vehicle: VehicleRealtimeRow; selected: boolean; onSelect: (vin: string) => void }) {
  const status = vehicleStatus(vehicle);
  return (
    <Button theme="borderless" type="tertiary" className={`v2-vehicle-row ${selected ? 'is-selected' : ''}`} onClick={() => onSelect(vehicle.vin)}>
      <i className={`v2-status-dot is-${status}`} />
      <span className="v2-vehicle-identity"><strong>{vehicle.plate || '未绑定车牌'}</strong><small>{vehicle.vin}</small></span>
      <span className="v2-vehicle-motion"><strong>{formatNumber(vehicle.speedKmh, 1)} <small>km/h</small></strong><small>{statusLabel(status)}</small></span>
    </Button>
  );
});

const MemoFleetMap = memo(FleetMap);

function VehicleDetailCard({
  vehicle,
  monitorReturn,
  onCollapse,
  onClear
}: {
  vehicle: VehicleRealtimeRow;
  monitorReturn: string;
  onCollapse: () => void;
  onClear: () => void;
}) {
  const [sourceEvidenceOpen, setSourceEvidenceOpen] = useState(false);
  const card = useMonitorVehicleCard(vehicle.vin, vehicle, true);
  const detail = card.detail.data;
  const activeAlerts = card.activeAlerts.data;
  const telemetry = card.telemetry?.data;
  const address = card.address.data;
  const status = vehicleStatus(vehicle);
  // The realtime row is joined to vehicle_daily_mileage with stat_date = CURDATE().
  // Vehicle detail mileage is ordered by recency and may start with yesterday, so it
  // must never be used as a fallback for a metric explicitly labelled "今日里程".
  const dailyMileage = vehicle.todayMileageAvailable === true ? vehicle.todayMileageKm : undefined;
  const latestAlert = activeAlerts?.items[0];
  const mileageLabel = vehicle.primaryProtocol === 'JT808' ? 'GPS 总里程' : '仪表盘总里程';
  const encodedVin = encodeURIComponent(vehicle.vin);
  const accessSource = detail?.profile?.accessProvider || vehicle.locationSource;
  const workflowLinks = [
    ['单车详情', `/vehicles/${encodedVin}`],
    ['轨迹回放', `/tracks?vin=${encodedVin}`],
    ['历史数据', `/history?vin=${encodedVin}`],
    ['里程查询', `/statistics?vins=${encodedVin}`]
  ] as const;
  const gbHighlights = (telemetry?.values ?? []).filter((item) => item.protocol === 'GB32960' && [
    'fuel_cell_voltage_v', 'fuel_cell_current_a', 'hydrogen_consumption_kg_per_100km',
    'hydrogen_concentration_percent', 'hydrogen_pressure_mpa', 'hydrogen_temperature_c',
    'engine_speed_rpm', 'total_voltage_v', 'total_current_a'
  ].includes(item.key)).slice(0, 9);
  return (
    <Card className="v2-vehicle-detail" bodyStyle={{ padding: 0 }}>
      <div className="v2-detail-body" role="region" aria-label={`${vehicle.plate || vehicle.vin}车辆详情`}>
        <div className="v2-detail-shell-header">
          <div className="v2-detail-controls">
            <Button size="small" theme="light" type="tertiary" icon={<IconChevronRight />} aria-label="收起车辆详情" title="收起到地图右侧" onClick={onCollapse} />
            <Button size="small" theme="light" type="danger" icon={<IconClose />} aria-label="取消选择车辆" title="取消选择车辆" onClick={onClear} />
          </div>
          <div className="v2-detail-title">
            <div><strong>{vehicle.plate || '未绑定车牌'}</strong><Tag className={`v2-status-text is-${status}`} color={status === 'driving' ? 'blue' : status === 'idle' || status === 'online' ? 'green' : status === 'alert' ? 'red' : 'grey'} type="light" size="small">{statusLabel(status)}</Tag></div>
            <small>{vehicle.vin}</small>
          </div>
          <nav className="v2-detail-actions" aria-label="车辆快捷操作">
            {workflowLinks.map(([label, path]) => <Link key={label} to={withMonitorReturn(path, monitorReturn)}><span>{label}</span><IconChevronRight aria-hidden="true" /></Link>)}
          </nav>
        </div>
      <section className="v2-detail-section v2-detail-report">
        <WorkspacePanelHeader
          variant="compact"
          title="最新上报"
          description="平台最新接收证据"
          meta={<Tag color={vehicle.online ? 'green' : 'grey'} type="light" size="small">{relativeFreshness(vehicle.lastSeen)}</Tag>}
        />
        <div className="v2-report-summary">
          <span className="is-time" title={vehicle.lastSeen || '暂无上报'}><small>平台接收时间</small><strong>{vehicle.lastSeen || '暂无上报'}</strong></span>
          <span title={vehicle.primaryProtocol || '未知'}><small>主协议</small><b>{vehicle.primaryProtocol || '未知'}</b></span>
          <span title={accessSource || '待补充'}><small>接入来源</small><b>{accessSource || '待补充'}</b></span>
        </div>
        <dl className="v2-detail-list">
          <div><dt>坐标</dt><dd><Button theme="borderless" type="tertiary" className="v2-detail-source-link" aria-label="查看全部位置来源" title="展开全部位置来源" onClick={() => setSourceEvidenceOpen(true)}>{hasRealtimeLocation(vehicle) ? `${vehicle.longitude.toFixed(6)}, ${vehicle.latitude.toFixed(6)}` : '—'}</Button></dd></div>
          <div><dt>位置</dt><dd>{hasRealtimeLocation(vehicle) ? address?.formattedAddress || '位置解析中' : '暂无实时位置'}</dd></div>
        </dl>
      </section>
      <section className="v2-detail-section">
        <WorkspacePanelHeader
          variant="compact"
          title="实时状态"
          description={accessSource || '来源待补充'}
          meta={<Tag color="blue" type="light" size="small">{vehicle.primaryProtocol || '未知协议'}</Tag>}
        />
        <div className="v2-metric-grid">
          <div className="is-speed"><small>速度</small><strong>{hasRealtimeSpeed(vehicle) ? formatNumber(vehicle.speedKmh, 1) : '—'}<em>{hasRealtimeSpeed(vehicle) ? 'km/h' : ''}</em></strong></div>
          <div className="is-soc"><small>SOC</small><strong>{hasRealtimeSOC(vehicle) ? formatNumber(vehicle.socPercent, 1) : '—'}<em>{hasRealtimeSOC(vehicle) ? '%' : ''}</em></strong></div>
          <div className="is-mileage"><small>{mileageLabel}</small><Button theme="borderless" type="tertiary" className="v2-metric-source-link" aria-label="查看总里程全部来源" title="展开全部里程来源" onClick={() => setSourceEvidenceOpen(true)}><span>{hasRealtimeMileage(vehicle) ? formatNumber(vehicle.totalMileageKm, 1) : '—'}<em>{hasRealtimeMileage(vehicle) ? 'km' : ''}</em></span><IconChevronRight /></Button></div>
          <div className="is-today"><small>今日里程</small><Button theme="borderless" type="tertiary" className="v2-metric-source-link" aria-label="查看今日里程全部来源" title="展开全部里程来源" onClick={() => setSourceEvidenceOpen(true)}><span>{dailyMileage == null ? '—' : formatNumber(dailyMileage, 1)}<em>{dailyMileage == null ? '' : 'km'}</em></span><IconChevronRight /></Button></div>
          <div className="is-status"><small>状态</small><strong>{statusLabel(status)}</strong></div>
          <div className={`is-alert${(activeAlerts?.total ?? 0) > 0 ? ' has-alerts' : ''}`}><small>当前告警</small><strong>{formatNumber(activeAlerts?.total ?? 0)}<em>条</em></strong></div>
        </div>
        {gbHighlights.length ? <div className="v2-gb-highlight-grid">{gbHighlights.map((item) => <div key={`${item.key}-${item.sourceField}`} title={item.description}><small>{item.label}</small><strong>{formatTelemetryValue(item.value, item.displayValue)}<em>{item.unit}</em></strong></div>)}</div> : null}
      </section>
      <section className="v2-detail-section">
        <WorkspacePanelHeader
          variant="compact"
          title="车辆信息"
          description="身份、车型与来源覆盖"
          meta={<Tag color={vehicle.onlineSourceCount ? 'green' : 'grey'} type="light" size="small">{vehicle.onlineSourceCount}/{vehicle.sourceCount} 在线</Tag>}
        />
        <dl className="v2-detail-list">
          <div><dt>VIN</dt><dd>{vehicle.vin}</dd></div>
          <div><dt>品牌 / 车型</dt><dd>{[detail?.profile?.brandName, detail?.profile?.modelName].filter(Boolean).join(' / ') || vehicle.oem || '待补充'}</dd></div>
          <div><dt>可用协议</dt><dd>{detail?.sources.join('、') || vehicle.protocols.join('、') || '未知'}</dd></div>
          <div><dt>接入供应商</dt><dd>{detail?.profile?.accessProvider || '待补充'}</dd></div>
          <div><dt>来源覆盖</dt><dd>{vehicle.onlineSourceCount}/{vehicle.sourceCount}</dd></div>
          <div><dt>告警状态</dt><dd>{latestAlert ? `${latestAlert.ruleName} · ${latestAlert.severity}` : '无当前业务告警'}</dd></div>
        </dl>
      </section>
      <VehicleSourceEvidencePanel vin={vehicle.vin} compact open={sourceEvidenceOpen} onOpenChange={setSourceEvidenceOpen} />
      </div>
    </Card>
  );
}

export default function MonitorPage() {
  const [routeParams, setRouteParams] = useSearchParams();
  const initialContextRef = useRef(parseMonitorRouteContext(routeParams));
  const initialContext = initialContextRef.current;
  const mobileLayout = useMobileLayout(760);
  const [mode, setMode] = useState<'map' | 'list'>(initialContext.mode);
  const [mobileEntryOpen, setMobileEntryOpen] = useState(false);
  const [listOffset, setListOffset] = useState(initialContext.listOffset);
  const [listLimit, setListLimit] = useState(initialContext.listLimit);
  const [keyword, setKeyword] = useState(initialContext.keyword);
  const [batchSearchOpen, setBatchSearchOpen] = useState(false);
  const [filtersCollapsed, setFiltersCollapsed] = useState(true);
  const deferredKeyword = useDeferredValue(keyword);
  const searchTerms = useMemo(() => parseMonitorSearchTerms(keyword), [keyword]);
  const [protocol, setProtocol] = useState(initialContext.protocol);
  const [status, setStatus] = useState(initialContext.status);
  const [selectedVin, setSelectedVin] = useState(initialContext.selectedVin);
  const [detailOpen, setDetailOpen] = useState(initialContext.detailOpen);
  const [viewport, setViewport] = useState<MonitorViewport>(initialContext.viewport);
  const updateViewport = useCallback((next: MonitorViewport) => {
    setViewport((current) => current.zoom === next.zoom && current.bounds === next.bounds ? current : next);
  }, []);
  const filters = useMemo(() => ({ keyword: deferredKeyword, protocol, status }), [deferredKeyword, protocol, status]);
  const monitorReturn = useMemo(() => buildMonitorPath({
    mode, keyword, protocol, status, selectedVin, detailOpen, viewport, listOffset, listLimit
  }), [detailOpen, keyword, listLimit, listOffset, mode, protocol, selectedVin, status, viewport]);
  useEffect(() => {
    const next = new URL(monitorReturn, 'https://vehicle-platform.invalid').searchParams;
    if (next.toString() !== routeParams.toString()) setRouteParams(next, { replace: true });
  }, [monitorReturn, routeParams, setRouteParams]);
  const listScope = useMemo(() => monitorFilterScope(filters), [filters]);
  const listParams = useMemo(() => {
    const params = monitorQueryParams(filters, listLimit);
    params.set('offset', String(listOffset));
    return params;
  }, [filters, listLimit, listOffset]);
  const trackedVin = mode === 'map' ? selectedVin : '';
  const { summary, vehicles, map, selectedVehicle } = useMonitorData(filters, viewport, trackedVin, mode === 'map', mode === 'map');
  const realtimeListQuery = useQuery<Page<VehicleRealtimeRow>>({
    queryKey: ['monitor', 'vehicle-list', listScope, listLimit, listOffset],
    queryFn: ({ signal }) => api.vehicleRealtime(listParams, signal),
    enabled: mode === 'list', placeholderData: retainPreviousPageWithinScope<Page<VehicleRealtimeRow>>(listScope, 2), refetchInterval: mode === 'list' ? MONITOR_REFRESH.fleet : false,
    gcTime: QUERY_MEMORY.highVolumeGcTime,
    ...LIVE_QUERY_POLICY
  });
  const rows = useMemo(() => {
    const data = vehicles.data?.items ?? [];
    if (status === 'driving' || status === 'idle') return data.filter((vehicle) => vehicleStatus(vehicle) === status);
    return data;
  }, [status, vehicles.data?.items]);
  const listRows = realtimeListQuery.data?.items ?? EMPTY_VEHICLES;
  const activeBatchRows = mode === 'map' ? rows : listRows;
  const activeBatchQuery = mode === 'map' ? vehicles : realtimeListQuery;
  const filterTransitionPending = keyword !== deferredKeyword || activeBatchQuery.isLoading;
  const batchSearchPending = searchTerms.length > 1 && filterTransitionPending;
  const batchMatch = useMemo(() => {
    const identities = new Set<string>();
    for (const vehicle of activeBatchRows) {
      identities.add(vehicle.vin.toLocaleUpperCase());
      if (vehicle.plate) identities.add(vehicle.plate.toLocaleUpperCase());
    }
    const missing = searchTerms.filter((term) => !identities.has(term));
    return { matched: searchTerms.length - missing.length, missing };
  }, [activeBatchRows, searchTerms]);
  const visibleRows = filterTransitionPending ? [] : rows;
  const batchStatus = batchSearchPending
    ? `正在查找 ${searchTerms.length} 辆`
    : batchMatch.missing.length
      ? `已找到 ${batchMatch.matched}/${searchTerms.length} · 未找到 ${batchMatch.missing.length} 辆`
      : `已找到 ${batchMatch.matched}/${searchTerms.length}`;
  const batchStatusTitle = batchMatch.missing.length
    ? `未找到：${batchMatch.missing.join('、')}`
    : searchTerms.join('、');
  const visibleListRows = filterTransitionPending ? EMPTY_VEHICLES : listRows;
  const visibleListTotal = filterTransitionPending ? 0 : (realtimeListQuery.data?.total ?? 0);
  const selected = selectedVin
    ? rows.find((vehicle) => vehicle.vin === selectedVin) ?? selectedVehicle.data?.items[0]
    : undefined;
  const selectVehicle = useCallback((vin: string) => {
    setSelectedVin(vin);
    setDetailOpen(true);
    setMode('map');
  }, []);
  const clearSelection = useCallback(() => {
    setSelectedVin('');
    setDetailOpen(false);
  }, []);
  const selectMapVehicle = useCallback((vehicle: VehicleRealtimeRow) => selectVehicle(vehicle.vin), [selectVehicle]);
  const collapseDetail = useCallback(() => setDetailOpen(false), []);
  const expandDetail = useCallback(() => setDetailOpen(true), []);
  const changeMonitorMode = useCallback((nextMode: 'map' | 'list') => {
    setMode(nextMode);
    if (nextMode === 'list') setDetailOpen(false);
  }, []);
  const clearFilters = useCallback(() => {
    setKeyword('');
    setProtocol('');
    setStatus('');
    setListOffset(0);
  }, []);
  const activeFilterCount = Number(Boolean(keyword.trim())) + Number(Boolean(protocol)) + Number(Boolean(status));
  const driving = rows.filter((vehicle) => vehicleStatus(vehicle) === 'driving').length;
  const idle = rows.filter((vehicle) => vehicleStatus(vehicle) === 'idle').length;
  const offline = rows.filter((vehicle) => vehicleStatus(vehicle) === 'offline').length;
  const viewportLoad = mode === 'map'
    ? (map.data?.clusters.length
      ? `${map.data.clusters.length} 个聚合 · ${map.data.points.length} 个车辆点`
      : `${map.data?.points.length ?? 0} 个车辆点`)
    : `${realtimeListQuery.data?.items.length ?? 0} / ${realtimeListQuery.data?.total ?? 0} 辆`;
  const lastSyncAt = vehicles.dataUpdatedAt ? new Date(vehicles.dataUpdatedAt) : undefined;

  return (
    <div className="v2-monitor-page">
      <Card className="v2-filterbar" bodyStyle={{ padding: 0 }} aria-label="车辆筛选">
        <div id="monitor-filter-fields" className={`v2-monitor-filter-fields${filtersCollapsed ? ' is-mobile-collapsed' : ''}`} aria-label="筛选条件">
          <div className={`v2-search-field${searchTerms.length > 1 ? ' is-batch' : ''}`}>
            <Input
              aria-label="搜索车辆"
              prefix={<IconSearch />}
              value={keyword}
              onChange={(value) => { setKeyword(value); setListOffset(0); }}
              onPaste={(event) => {
                const pastedTerms = parseMonitorSearchTerms(event.clipboardData.getData('text'));
                if (pastedTerms.length <= 1) return;
                event.preventDefault();
                setKeyword(pastedTerms.join('，'));
                setListOffset(0);
              }}
              placeholder="车牌 / VIN；可批量粘贴车牌"
              suffix={<Button className="v2-search-batch-action" size="small" theme="borderless" onClick={() => setBatchSearchOpen(true)}>批量</Button>}
            />
            {searchTerms.length > 1 ? <span className={`v2-search-batch-count${batchMatch.missing.length && !batchSearchPending ? ' has-missing' : ''}`} aria-live="polite" title={searchTerms.length === MAX_MONITOR_SEARCH_TERMS ? `最多支持 ${MAX_MONITOR_SEARCH_TERMS} 条；${batchStatusTitle}` : batchStatusTitle}>{batchSearchPending ? `已识别 ${searchTerms.length} 辆` : `已找到 ${batchMatch.matched}/${searchTerms.length}`}</span> : null}
          </div>
          <span className="v2-sr-only" id="monitor-protocol-filter-label">协议</span>
          <Select value={protocol} onChange={(value) => { setProtocol(String(value)); setListOffset(0); }} aria-labelledby="monitor-protocol-filter-label" optionList={protocols.map((item) => ({ value: item, label: item || '全部协议' }))} />
          <span className="v2-sr-only" id="monitor-status-filter-label">在线状态</span>
          <Select value={status} onChange={(value) => { setStatus(String(value)); setListOffset(0); }} aria-labelledby="monitor-status-filter-label" optionList={statuses.map((item) => ({ value: item, label: item === 'no_location' ? '无实时位置' : item ? statusLabel(item as never) : '全部状态' }))} />
          <Button className="v2-filter-reset" icon={<IconRefresh />} disabled={activeFilterCount === 0} onClick={clearFilters}>清空</Button>
        </div>
        <div className="v2-monitor-filter-actions" aria-label="监控操作">
          {mobileLayout ? <Button
            className={`v2-monitor-filter-toggle${activeFilterCount ? ' has-filters' : ''}`}
            theme="light"
            icon={<IconFilter />}
            aria-controls="monitor-filter-fields"
            aria-expanded={!filtersCollapsed}
            aria-label={`${filtersCollapsed ? '展开' : '收起'}车辆筛选，当前 ${activeFilterCount} 个条件`}
            onClick={() => setFiltersCollapsed((value) => !value)}
          >
            {filtersCollapsed ? '筛选' : '收起'}{activeFilterCount ? <b>{activeFilterCount}</b> : null}
          </Button> : <span
            className={`v2-filter-live-status${activeFilterCount ? ' has-filters' : ''}`}
            role="status"
            aria-label={`搜索和筛选条件修改后自动生效，已启用 ${activeFilterCount} 个条件`}
            title="搜索和筛选条件修改后自动生效"
          >
            <IconFilter aria-hidden="true" />
            <span className="v2-filter-live-status-label">自动生效</span>
            {activeFilterCount ? <b>{activeFilterCount}</b> : null}
          </span>}
          <SegmentedTabs
            ariaLabel="监控视图"
            className="v2-monitor-mode"
            value={mode}
            items={MONITOR_VIEW_ITEMS}
            onChange={changeMonitorMode}
            variant="filled"
          />
          <Button className="v2-monitor-mobile-entry" theme="light" icon={<IconQrCode />} aria-label="打开手机端入口" onClick={() => setMobileEntryOpen(true)}><span className="v2-monitor-mobile-entry-label">手机端</span></Button>
        </div>
      </Card>
      {batchSearchOpen ? <BatchVehicleSearchDialog initialValue={searchTerms.join('\n')} onClose={() => setBatchSearchOpen(false)} onApply={(value) => { setKeyword(value); setListOffset(0); setBatchSearchOpen(false); }} /> : null}

      <Card className="v2-kpis" bodyStyle={{ padding: 0 }} aria-label="车辆整体统计">
        {[
          { label: '车辆总数', value: formatNumber(summary.data?.totalVehicles ?? vehicles.data?.total ?? rows.length), tone: 'fleet', priority: 'primary', unit: '辆' },
          { label: '当前在线', value: formatNumber(summary.data?.onlineVehicles ?? rows.length - offline), tone: 'online', priority: 'primary', unit: '辆' },
          { label: '当前离线', value: formatNumber(summary.data?.offlineVehicles ?? offline), tone: 'offline', priority: 'standard', unit: '辆' },
          { label: '行驶车辆', value: formatNumber(summary.data?.drivingVehicles ?? driving), tone: 'driving', priority: 'standard', unit: '辆' },
          { label: '静止车辆', value: formatNumber(summary.data?.idleVehicles ?? idle), tone: 'idle', priority: 'standard', unit: '辆' },
          { label: '告警车辆', value: summary.data?.alertDataAvailable ? formatNumber(summary.data.alertVehicles) : '—', tone: 'alert', priority: 'standard', unit: '辆' },
          { label: '今日上报', value: formatNumber(summary.data?.frameToday ?? 0), tone: 'today', priority: 'support', unit: '条' },
          { label: '无实时位置', value: formatNumber(summary.data?.noLocationVehicles ?? 0), tone: 'missing', priority: 'support', unit: '辆' }
        ].map(({ label, value, tone, priority, unit }) => <div key={label} className={`v2-kpi is-${tone} is-${priority}`}><small>{label}</small><strong>{value}<em>{unit}</em></strong></div>)}
      </Card>

      {vehicles.isError ? <InlineError message={vehicles.error instanceof Error ? vehicles.error.message : '车辆数据加载失败'} onRetry={() => vehicles.refetch()} /> : null}
      {mode === 'list' && realtimeListQuery.isError ? <InlineError message={realtimeListQuery.error instanceof Error ? realtimeListQuery.error.message : '车辆列表加载失败'} onRetry={() => realtimeListQuery.refetch()} /> : null}
      {mode === 'map' ? <section className={`v2-monitor-workspace${selected && detailOpen ? ' is-detail-open' : ''}${selected && !detailOpen ? ' is-detail-collapsed' : ''}`}>
        <div className="v2-vehicle-rail">
          <header><strong>车辆列表</strong><span>{batchSearchPending ? '查询中' : `${formatNumber(vehicles.data?.total ?? visibleRows.length)} 辆`}</span></header>
          <div className={`v2-rail-search${batchMatch.missing.length && !batchSearchPending ? ' has-missing' : ''}`} title={searchTerms.length > 1 ? batchStatusTitle : undefined}><IconSearch /><span>{searchTerms.length > 1 ? batchStatus : deferredKeyword ? `正在筛选“${deferredKeyword}”` : '按最新上报排序'}</span></div>
          <div className="v2-vehicle-scroll">
            {vehicles.isLoading || batchSearchPending ? <div className="v2-list-loading"><span className="v2-spinner" />{batchSearchPending ? `正在查找 ${searchTerms.length} 辆车` : '加载车辆'}</div> : null}
            {!vehicles.isLoading && !batchSearchPending && visibleRows.length === 0 ? <EmptyState /> : null}
            {visibleRows.map((vehicle) => <VehicleRow key={vehicle.vin} vehicle={vehicle} selected={vehicle.vin === selectedVin} onSelect={selectVehicle} />)}
          </div>
          <footer>{searchTerms.length > 1 && !batchSearchPending ? batchStatus : `当前载入 ${visibleRows.length} / ${vehicles.data?.total ?? visibleRows.length} 辆`}</footer>
        </div>
        <MemoFleetMap
          vehicles={visibleRows}
          monitorMap={filterTransitionPending ? undefined : map.data}
          selectedVin={selectedVin || undefined}
          onSelect={selectMapVehicle}
          onSelectVin={selectVehicle}
          onViewportChange={updateViewport}
          initialViewport={initialContext.hasViewport ? initialContext.viewport : undefined}
        />
        {selected && detailOpen ? (
          <VehicleDetailCard
            vehicle={selected}
            monitorReturn={monitorReturn}
            onCollapse={collapseDetail}
            onClear={clearSelection}
          />
        ) : null}
        {selected && !detailOpen ? (
          <Card className="v2-detail-peek" bodyStyle={{ padding: 0 }}>
            <Button theme="borderless" type="tertiary" aria-label="展开车辆详情" title={`展开 ${selected.plate || selected.vin} 的车辆详情`} onClick={expandDetail}>
              <IconChevronLeft />
              <i className={`v2-status-dot is-${vehicleStatus(selected)}`} />
              <span>{selected.plate || '未绑定车牌'}</span>
            </Button>
          </Card>
        ) : null}
      </section> : <MonitorVehicleTable rows={visibleListRows} total={visibleListTotal} page={Math.floor(listOffset / listLimit) + 1} totalPages={Math.max(1, Math.ceil(visibleListTotal / listLimit))} limit={listLimit} loading={filterTransitionPending || realtimeListQuery.isFetching} mobile={mobileLayout} onSelect={selectVehicle} onPage={(page) => setListOffset((page - 1) * listLimit)} onLimit={(next) => { setListLimit(next); setListOffset(0); }} />}

      <Card className="v2-event-strip" bodyStyle={{ padding: 0 }} aria-label="实时数据状态">
        <div className="v2-event-sync">
          <Tag className="v2-monitor-live-tag" color="green" type="light" size="small"><IconRefresh aria-hidden="true" />{vehicles.isFetching ? '正在同步' : '数据已同步'}</Tag>
          <span><strong>实时数据</strong><small>{visibleRows.length.toLocaleString('zh-CN')} 辆已载入</small></span>
        </div>
        <div className="v2-event-load"><small>{mode === 'map' ? '地图载荷' : '列表载荷'}</small><span>{viewportLoad}</span></div>
        <div className="v2-refresh-cadence">
          <Tag color="blue" type="light" size="small"><IconRefresh aria-hidden="true" />智能刷新</Tag>
          <span>重点 {MONITOR_REFRESH.selected / 1000}s · 车队 {MONITOR_REFRESH.fleet / 1000}s · 统计 {MONITOR_REFRESH.summary / 1000}s</span>
        </div>
        <time dateTime={lastSyncAt?.toISOString()}><span><small>最近同步</small><b>{lastSyncAt ? lastSyncAt.toLocaleTimeString('zh-CN', { hour12: false }) : '等待数据'}</b></span></time>
      </Card>
      {mobileEntryOpen ? <MobileEntry onClose={() => setMobileEntryOpen(false)} /> : null}
    </div>
  );
}
