import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { afterEach, expect, test, vi } from 'vitest';
import OperationsPage from './OperationsPage';

const mocks = vi.hoisted(() => ({
  opsHealth: vi.fn(), sourceReadiness: vi.fn(), session: vi.fn(), vehicleCoverage: vi.fn(),
  vehicleSourceDiagnostic: vi.fn(), updateVehicleSourcePolicy: vi.fn()
}));
vi.mock('../../api/client', () => ({ api: mocks }));

afterEach(() => { cleanup(); Object.values(mocks).forEach((mock) => mock.mockReset()); });

function seedSession() {
  mocks.session.mockResolvedValue({ name: '平台管理员', role: 'admin', userType: 'admin', authMode: 'enforce', menuKeys: ['operations'] });
}

test('reconciles service identities with bound and identity-required vehicles', async () => {
  seedSession();
  mocks.opsHealth.mockResolvedValue({
    linkHealth: [], kafkaLag: 0, activeConnections: 10, capacityFindings: [], redisOnlineKeys: 5,
    tdengineWritable: true, mysqlWritable: true,
    runtime: { platformRelease: 'test-release', dataMode: 'production', requestTimeoutMs: 5000, amapSecurityProxyEnabled: true, amapSecurityCodeExposed: false }
  });
  mocks.sourceReadiness.mockResolvedValue({
    totalVehicles: 1035, boundVehicles: 1024, identityRequiredVehicles: 11, onlineVehicles: 234,
    kafkaLag: 0, activeConnections: 10, redisOnlineKeys: 5, platformRelease: 'test-release', sources: []
  });
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  render(<QueryClientProvider client={client}><OperationsPage /></QueryClientProvider>);

  expect(await screen.findByText('1035 / 234')).toBeInTheDocument();
  for (const key of [['ops-health-v2'], ['ops-source-readiness-v2']]) {
    const query = client.getQueryCache().find({ queryKey: key });
    const liveOptions = query?.options as { refetchIntervalInBackground?: boolean; refetchOnWindowFocus?: boolean };
    expect(liveOptions.refetchIntervalInBackground).toBe(false);
    expect(liveOptions.refetchOnWindowFocus).toBe(true);
  }
  expect(screen.getByText('服务身份 / 在线')).toBeInTheDocument();
  expect(screen.getByText('已绑定 1024 · 待绑定 11')).toBeInTheDocument();
  expect(screen.queryByText('统一车辆视角')).not.toBeInTheDocument();
});

test('keeps health evidence visible when source readiness fails and retries that section', async () => {
  seedSession();
  mocks.opsHealth.mockResolvedValue({
    linkHealth: [], kafkaLag: 0, activeConnections: 10, capacityFindings: [], redisOnlineKeys: 5,
    tdengineWritable: true, mysqlWritable: true,
    runtime: { platformRelease: 'test-release', dataMode: 'production', requestTimeoutMs: 5000, amapSecurityProxyEnabled: true, amapSecurityCodeExposed: false }
  });
  mocks.sourceReadiness.mockRejectedValueOnce(new Error('来源就绪度暂时不可用')).mockResolvedValueOnce({
    totalVehicles: 1035, boundVehicles: 1024, identityRequiredVehicles: 11, onlineVehicles: 234,
    kafkaLag: 0, activeConnections: 10, redisOnlineKeys: 5, platformRelease: 'test-release', sources: []
  });
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  render(<QueryClientProvider client={client}><OperationsPage /></QueryClientProvider>);

  expect(await screen.findByText('来源就绪度暂时不可用')).toBeInTheDocument();
  expect(screen.getByText('test-release')).toBeInTheDocument();
  fireEvent.click(screen.getByRole('button', { name: /重试/ }));

  expect(await screen.findByText('1035 / 234')).toBeInTheDocument();
  expect(screen.queryByText('来源就绪度暂时不可用')).not.toBeInTheDocument();
  expect(mocks.sourceReadiness).toHaveBeenCalledTimes(2);
});

test('fuzzy searches a vehicle and renders all source diagnosis evidence', async () => {
  seedSession();
  mocks.opsHealth.mockResolvedValue({
    linkHealth: [], kafkaLag: 0, activeConnections: 10, capacityFindings: [], redisOnlineKeys: 5,
    tdengineWritable: true, mysqlWritable: true,
    runtime: { platformRelease: 'test-release', dataMode: 'production', requestTimeoutMs: 5000, amapSecurityProxyEnabled: true, amapSecurityCodeExposed: false }
  });
  mocks.sourceReadiness.mockResolvedValue({ totalVehicles: 1, boundVehicles: 1, identityRequiredVehicles: 0, onlineVehicles: 1, sources: [] });
  mocks.vehicleCoverage.mockResolvedValue({ items: [{ vin: 'VIN001', plate: '粤A00001', protocols: ['JT808'], missingProtocols: [], sourceStatus: [], sourceCount: 2, onlineSourceCount: 2, online: true, lastSeen: '', bindingStatus: 'bound' }], total: 1, limit: 20, offset: 0 });
  mocks.vehicleSourceDiagnostic.mockResolvedValue({
    evidence: {
      vin: 'VIN001', plate: '粤A00001', mileageDate: '2026-07-16', recommendedLocationProtocol: 'JT808',
      recommendedLocationLabel: 'G7', locationConflict: true, conflictDistanceM: 233,
      locationSources: [{
        protocol: 'JT808', sourceLabel: 'G7', terminalLabel: '终端 133****0001', sourceKind: 'PLATFORM', sourceRef: 'a'.repeat(64),
        selectedWithinProtocol: true, recommended: true, enabled: true, priority: 20, online: true, qualityStatus: 'OK', qualityReason: '',
        longitude: 113.1, latitude: 23.1, speedKmh: 30, totalMileageKm: 1000, eventTime: '2026-07-16 10:00:00',
        receivedAt: '2026-07-16 10:00:01', firstSeenAt: '2026-03-01 08:00:00', reportIntervalSec: 10, reportSampleCount: 1000,
        selectionReason: '当前融合推荐'
      }],
      mileageSources: [], comparison: { locationMaxDistanceM: 233, totalMileageDeltaKm: 0, dailyMileageDeltaKm: 0, reportTimeDeltaSeconds: 0 }, asOf: ''
    },
    policy: { vin: 'VIN001', version: 1, updatedBy: 'system', updatedAt: '', audit: [] },
    recommendationReason: '当前推荐 G7', refreshHint: '下一次有效上报后重新选举'
  });
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  render(<QueryClientProvider client={client}><OperationsPage /></QueryClientProvider>);
  fireEvent.change(screen.getByLabelText('按车牌或 VIN 搜索诊断车辆'), { target: { value: '粤A' } });
  expect(await screen.findByText('粤A00001')).toBeInTheDocument();
  fireEvent.click(screen.getByText('粤A00001'));
  expect(await screen.findByText('当前推荐 G7')).toBeInTheDocument();
  expect(screen.getByText('终端 133****0001')).toBeInTheDocument();
  expect(screen.getByText('10s')).toBeInTheDocument();
  await waitFor(() => expect(mocks.vehicleSourceDiagnostic).toHaveBeenCalledWith('VIN001', expect.any(AbortSignal)));
});
