import { describe, expect, test } from 'vitest';
import {
  buildDataCapabilityRadar,
  buildReplayRawLookupWindow,
  getCommandPriorityItems,
  getMileageSourceDecisions,
  getSampleBoundaryCopy,
  getStatsInterpretationItems,
  getVehicleDiagnosticSteps,
  getVehicleDetailDigest,
  getVehicleSourceResponsibilityRows
} from './viewModel';
import type { VehicleRecord } from './types';

describe('buildReplayRawLookupWindow', () => {
  test('builds a focused China-time RAW lookup window around a replay node', () => {
    const timestamp = Date.parse('2026-07-09T09:53:20+08:00');

    expect(buildReplayRawLookupWindow(timestamp)).toEqual({
      dateFrom: '2026-07-09T09:51:20+08:00',
      dateTo: '2026-07-09T09:55:20+08:00'
    });
  });
});

describe('getMileageSourceDecisions', () => {
  test('selects one trusted mileage source without summing multiple protocols', () => {
    const vehicle = testVehicle({ id: '004', protocol: 'GB32960', totalMileageKm: 1000 });
    vehicle.sources[0].todayMileageKm = 12;
    vehicle.sources[0].lastSeen = '40 秒前';
    vehicle.sources.push({
      id: '004-JT808',
      protocol: 'JT808',
      sourceName: 'JT808 来源',
      endpoint: '/api/realtime/locations',
      platformAccount: '测试平台',
      status: 'online',
      latencyMs: 60,
      lastSeen: '5 秒前',
      totalMileageKm: 1000.8,
      todayMileageKm: 14,
      fieldCount: 15
    });

    const [decision] = getMileageSourceDecisions([vehicle]);

    expect(decision).toMatchObject({
      selectedProtocol: 'JT808',
      selectedDailyMileageKm: 14,
      selectedTotalMileageKm: 1000.8,
      candidateCount: 2,
      status: 'ready'
    });
    expect(decision.sources.map((source) => source.todayMileageKm)).toEqual([12, 14]);
    expect(decision.selectedDailyMileageKm).not.toBe(26);
  });

  test('marks vehicles without mileage as missing instead of inventing values', () => {
    const vehicle = testVehicle({ id: '005', protocol: 'YUTONG_MQTT' });
    vehicle.sources[0].totalMileageKm = undefined;
    vehicle.sources[0].todayMileageKm = undefined;

    const [decision] = getMileageSourceDecisions([vehicle]);

    expect(decision).toMatchObject({
      selectedProtocol: undefined,
      selectedDailyMileageKm: 0,
      selectedTotalMileageKm: 0,
      candidateCount: 0,
      status: 'missing'
    });
    expect(decision.detail).toContain('不展示里程');
  });
});

describe('getSampleBoundaryCopy', () => {
  test('keeps fallback samples clearly separated from production facts', () => {
    expect(getSampleBoundaryCopy('history-raw', false)).toMatchObject({
      title: 'Raw 样例记录已收起',
      actionLabel: '展开样例记录'
    });
    expect(getSampleBoundaryCopy('alert-events', true)).toMatchObject({
      title: '正在展示样例事件',
      actionLabel: '收起样例事件'
    });
    expect(getSampleBoundaryCopy('source-monitor', false)).toMatchObject({
      title: '样例来源已收起',
      actionLabel: '展开样例来源'
    });

    const allCopy = [
      getSampleBoundaryCopy('history-raw', true),
      getSampleBoundaryCopy('alert-events', true),
      getSampleBoundaryCopy('source-monitor', true)
    ];

    allCopy.forEach((copy) => {
      expect(copy.detail).toContain('不代表');
      expect(copy.detail).not.toContain('生产已接入');
    });
  });
});

function testVehicle({
  id,
  protocol,
  longitude = 121.4,
  latitude = 31.2,
  totalMileageKm
}: {
  id: string;
  protocol: VehicleRecord['sources'][number]['protocol'];
  longitude?: number;
  latitude?: number;
  totalMileageKm?: number;
}): VehicleRecord {
  return {
    id,
    plate: `沪A${id}`,
    vin: `VIN-${id}`,
    oem: '测试厂商',
    status: 'online',
    city: '上海',
    address: '测试地址',
    longitude,
    latitude,
    mapX: 50,
    mapY: 50,
    heading: 0,
    primarySourceId: `${id}-${protocol}`,
    sources: [{
      id: `${id}-${protocol}`,
      protocol,
      sourceName: `${protocol} 来源`,
      endpoint: '/api/realtime/locations',
      platformAccount: '测试平台',
      status: 'online',
      latencyMs: 80,
      lastSeen: '12 秒前',
      totalMileageKm,
      fieldCount: 18
    }],
    flatFields: {
      GB32960: {},
      JT808: {},
      YUTONG_MQTT: {}
    }
  };
}

describe('buildDataCapabilityRadar', () => {
  test('summarizes only source-backed capabilities for the realtime command surface', () => {
    const radar = buildDataCapabilityRadar({
      vehicles: [
        testVehicle({ id: '001', protocol: 'GB32960', totalMileageKm: 1024.5 }),
        testVehicle({ id: '002', protocol: 'JT808' })
      ],
      realtimeStatus: 'ready',
      realtimeTotal: 2,
      amapStatus: 'ready',
      rawQueryEnabled: true,
      trackQueryEnabled: true
    });

    expect(radar.map((item) => item.key)).toEqual([
      'realtime-location',
      'protocol-coverage',
      'amap-map',
      'raw-evidence',
      'mileage-stat'
    ]);
    expect(radar.find((item) => item.key === 'realtime-location')).toMatchObject({
      state: 'ready',
      metric: '2/2 台'
    });
    expect(radar.find((item) => item.key === 'protocol-coverage')).toMatchObject({
      state: 'partial',
      metric: '32960 1 / 808 1 / MQTT 0'
    });
    expect(radar.find((item) => item.key === 'mileage-stat')).toMatchObject({
      state: 'partial',
      metric: '1/2 来源'
    });
  });

  test('does not promote mock or unavailable infrastructure as production capability', () => {
    const radar = buildDataCapabilityRadar({
      vehicles: [],
      realtimeStatus: 'error',
      realtimeTotal: 0,
      amapStatus: 'error',
      rawQueryEnabled: false,
      trackQueryEnabled: false
    });

    expect(radar.every((item) => item.state !== 'ready')).toBe(true);
    expect(radar.find((item) => item.key === 'raw-evidence')).toMatchObject({
      state: 'unavailable',
      metric: '未启用'
    });
    expect(radar.map((item) => item.title).join(' ')).not.toContain('通知');
  });
});

describe('getVehicleDetailDigest', () => {
  test('condenses a selected vehicle into realtime, trust, and traceability cards', () => {
    const vehicle = testVehicle({ id: '003', protocol: 'JT808', totalMileageKm: 2048.6 });
    vehicle.sources.push({
      id: '003-GB32960',
      protocol: 'GB32960',
      sourceName: 'GB32960 来源',
      endpoint: '/api/realtime/locations',
      platformAccount: '测试平台',
      status: 'warning',
      latencyMs: 230,
      lastSeen: '4 分钟前',
      totalMileageKm: 2049.1,
      fieldCount: 22
    });

    const digest = getVehicleDetailDigest(vehicle, vehicle.sources[0]);

    expect(digest.map((item) => item.title)).toEqual(['实时状态', '来源可信度', '可追溯证据']);
    expect(digest[0]).toMatchObject({
      tone: 'ok',
      value: '0 km/h'
    });
    expect(digest[1]).toMatchObject({
      tone: 'warning',
      metric: '1/2 在线'
    });
    expect(digest[2]).toMatchObject({
      tone: 'ready',
      value: 'JT808 RAW'
    });
    expect(digest.map((item) => item.source).join(' ')).toContain('Redis');
    expect(digest.map((item) => item.source).join(' ')).toContain('TDengine');
  });
});

describe('getVehicleDiagnosticSteps', () => {
  test('builds an ordered production troubleshooting path for the selected vehicle', () => {
    const vehicle = testVehicle({ id: '006', protocol: 'JT808', totalMileageKm: 2048.6 });
    vehicle.sources[0].fieldCount = 0;
    vehicle.sources.push({
      id: '006-GB32960',
      protocol: 'GB32960',
      sourceName: 'GB32960 来源',
      endpoint: '/api/realtime/snapshots',
      platformAccount: '测试平台',
      status: 'online',
      latencyMs: 180,
      lastSeen: '10 秒前',
      totalMileageKm: 2102.6,
      fieldCount: 22
    });

    const steps = getVehicleDiagnosticSteps(vehicle, vehicle.sources[0]);

    expect(steps.map((item) => item.key)).toEqual(['realtime-state', 'source-consistency', 'evidence-loop']);
    expect(steps[0]).toMatchObject({
      title: '确认当前态',
      status: 'warning',
      action: 'overview'
    });
    expect(steps[0].detail).toContain('字段');
    expect(steps[1]).toMatchObject({
      title: '核对来源一致性',
      status: 'warning',
      action: 'sources'
    });
    expect(steps[1].detail).toContain('里程');
    expect(steps[2]).toMatchObject({
      title: '回查证据闭环',
      status: 'ready',
      action: 'history'
    });
    expect(steps[2].detail).toContain('TDengine');
  });
});

describe('getVehicleSourceResponsibilityRows', () => {
  test('turns protocol sources into an operations responsibility table', () => {
    const vehicle = testVehicle({ id: '007', protocol: 'JT808', totalMileageKm: 2048.6 });
    vehicle.sources[0].fieldCount = 0;
    vehicle.sources.push({
      id: '007-GB32960',
      protocol: 'GB32960',
      sourceName: 'GB32960 来源',
      endpoint: '/api/realtime/snapshots',
      platformAccount: '测试平台',
      status: 'online',
      latencyMs: 180,
      lastSeen: '10 秒前',
      totalMileageKm: 2102.6,
      fieldCount: 22
    }, {
      id: '007-YUTONG',
      protocol: 'YUTONG_MQTT',
      sourceName: '宇通 MQTT 来源',
      endpoint: 'mqtt://yutong/topic',
      platformAccount: '测试平台',
      status: 'offline',
      latencyMs: 900,
      lastSeen: '12 分钟前',
      fieldCount: 8
    });

    const rows = getVehicleSourceResponsibilityRows(vehicle, vehicle.sources[0]);

    expect(rows.map((row) => row.protocol)).toEqual(['JT808', 'GB32960', 'YUTONG_MQTT']);
    expect(rows[0]).toMatchObject({
      selected: true,
      status: 'warning',
      issueCount: 1,
      issueSummary: '字段缺失',
      mileageDeltaKm: 0
    });
    expect(rows[1]).toMatchObject({
      status: 'warning',
      issueSummary: '里程差异',
      mileageDeltaKm: 54
    });
    expect(rows[2]).toMatchObject({
      status: 'error',
      issueCount: 2,
      issueSummary: '来源离线 / 里程缺失'
    });
  });
});

describe('getStatsInterpretationItems', () => {
  test('summarizes trusted mileage, daily API, source consistency, and protocol coverage', () => {
    const ready = testVehicle({ id: '020', protocol: 'GB32960', totalMileageKm: 1000 });
    ready.sources[0].todayMileageKm = 12;

    const conflict = testVehicle({ id: '021', protocol: 'GB32960', totalMileageKm: 2000 });
    conflict.sources[0].todayMileageKm = 20;
    conflict.sources.push({
      id: '021-JT808',
      protocol: 'JT808',
      sourceName: 'JT808 来源',
      endpoint: '/api/realtime/locations',
      platformAccount: '测试平台',
      status: 'online',
      latencyMs: 60,
      lastSeen: '4 秒前',
      totalMileageKm: 2028,
      todayMileageKm: 22,
      fieldCount: 16
    });

    const missing = testVehicle({ id: '022', protocol: 'YUTONG_MQTT' });
    missing.sources[0].totalMileageKm = undefined;
    missing.sources[0].todayMileageKm = undefined;

    const items = getStatsInterpretationItems([ready, conflict, missing], 'ALL', false);

    expect(items.map((item) => item.key)).toEqual([
      'trusted-mileage',
      'daily-mileage-api',
      'source-consistency',
      'protocol-coverage'
    ]);
    expect(items[0]).toMatchObject({
      metric: '1/3',
      tone: 'error'
    });
    expect(items[1]).toMatchObject({
      metric: '待接入',
      tone: 'waiting'
    });
    expect(items[2]).toMatchObject({
      metric: '1/1 需关注',
      tone: 'warning'
    });
    expect(items[3]).toMatchObject({
      metric: '32960 2 / 808 1 / MQTT 1',
      tone: 'ready'
    });
  });
});

describe('getCommandPriorityItems', () => {
  test('prioritizes source health, coordinate, mileage, and field coverage issues from realtime vehicles', () => {
    const healthy = testVehicle({ id: '010', protocol: 'GB32960', totalMileageKm: 1024 });
    healthy.sources[0].fieldCount = 20;
    healthy.flatFields.GB32960 = {
      'gb32960.vehicle.speed_kmh': 20,
      'gb32960.vehicle.total_mileage_km': 1024
    };

    const offline = testVehicle({ id: '011', protocol: 'JT808', totalMileageKm: 2048 });
    offline.status = 'offline';
    offline.sources[0].status = 'offline';
    offline.sources[0].fieldCount = 0;

    const missingCoordinate = testVehicle({
      id: '012',
      protocol: 'YUTONG_MQTT',
      longitude: 0,
      latitude: 0,
      totalMileageKm: 4096
    });
    missingCoordinate.sources[0].fieldCount = 12;
    missingCoordinate.flatFields.YUTONG_MQTT = {
      'yutong_mqtt.data.longitude': 0,
      'yutong_mqtt.data.latitude': 0
    };

    const missingMileage = testVehicle({ id: '013', protocol: 'GB32960' });
    missingMileage.sources[0].totalMileageKm = undefined;
    missingMileage.sources[0].todayMileageKm = undefined;
    missingMileage.sources[0].fieldCount = 0;

    const priorities = getCommandPriorityItems([
      healthy,
      offline,
      missingCoordinate,
      missingMileage
    ]);

    expect(priorities.map((item) => item.key)).toEqual([
      'source-health',
      'coordinate',
      'mileage',
      'field-coverage'
    ]);
    expect(priorities[0]).toMatchObject({
      value: '1',
      tone: 'error',
      vehicleIds: ['011']
    });
    expect(priorities[1]).toMatchObject({
      value: '1',
      tone: 'warning',
      vehicleIds: ['012']
    });
    expect(priorities[2]).toMatchObject({
      value: '1',
      tone: 'warning',
      vehicleIds: ['013']
    });
    expect(priorities[3]).toMatchObject({
      value: '2',
      tone: 'warning',
      vehicleIds: ['011', '013']
    });
  });
});
