import { isValidAMapCoordinate } from '../integrations/amap';
import type { Protocol } from './types';

export type RawCoordinateEvidence = {
  latitude: number;
  longitude: number;
  latitudeKey: string;
  longitudeKey: string;
  speedKmh?: number;
  totalMileageKm?: number;
  totalMileageKey?: string;
  totalMileageUnitEvidence?: 'km' | 'm->km';
  directionDeg?: number;
  altitudeM?: number;
};

export type RawCoordinateAddressInput = {
  status: 'disabled' | 'loading' | 'ready' | 'unavailable' | 'error';
  provider?: string;
  address?: string;
  region?: string;
  error?: string;
};

export type RawCoordinateAddressEvidence = {
  status: 'ready' | 'loading' | 'unavailable' | 'error';
  label: string;
  detail: string;
  evidence: string;
  tone: 'ready' | 'warning' | 'waiting' | 'error';
};

function rawNumberValue(value: unknown) {
  if (value == null || value === '') {
    return undefined;
  }
  const number = Number(String(value).trim());
  return Number.isFinite(number) ? number : undefined;
}

function rawFieldScore(key: string) {
  const normalized = key.toLowerCase();
  if (normalized.includes('.location.')) return 0;
  if (normalized.includes('.data.') && !normalized.includes('.root.data.')) return 1;
  if (normalized.includes('.root.data.')) return 2;
  return 3;
}

function pickRawNumberField(fields: Record<string, unknown>, matcher: (key: string) => boolean) {
  return Object.entries(fields)
    .map(([key, value]) => ({ key, value: rawNumberValue(value) }))
    .filter((item): item is { key: string; value: number } => item.value != null && matcher(item.key.toLowerCase()))
    .sort((left, right) => rawFieldScore(left.key) - rawFieldScore(right.key))[0];
}

function rawMileageProjection(protocol: Protocol, mileage?: { key: string; value: number }) {
  if (!mileage) {
    return undefined;
  }
  const normalizedKey = mileage.key.toLowerCase();
  if (normalizedKey.endsWith('.total_mileage_m')) {
    return { value: mileage.value / 1000, unitEvidence: 'm->km' as const };
  }
  if (
    protocol === 'YUTONG_MQTT' &&
    normalizedKey.endsWith('.total_mileage') &&
    !normalizedKey.endsWith('.total_mileage_km')
  ) {
    return { value: mileage.value / 1000, unitEvidence: 'm->km' as const };
  }
  return { value: mileage.value, unitEvidence: 'km' as const };
}

export function rawCoordinateEvidence(
  protocol: Protocol,
  fields: Record<string, unknown>
): RawCoordinateEvidence | undefined {
  const latitude = pickRawNumberField(fields, (key) =>
    key === 'latitude' ||
    key.endsWith('.latitude') ||
    key.endsWith('.lat')
  );
  const longitude = pickRawNumberField(fields, (key) =>
    key === 'longitude' ||
    key.endsWith('.longitude') ||
    key.endsWith('.lng') ||
    key.endsWith('.lon')
  );
  if (!latitude || !longitude || !isValidAMapCoordinate(longitude.value, latitude.value)) {
    return undefined;
  }
  const speed = pickRawNumberField(fields, (key) =>
    key.endsWith('.speed_kmh') ||
    key.endsWith('.speed_kph') ||
    key.endsWith('.meter_speed')
  );
  const mileage = pickRawNumberField(fields, (key) =>
    key.endsWith('.total_mileage_km') ||
    key.endsWith('.total_mileage_m') ||
    key.endsWith('.total_mileage')
  );
  const mileageProjection = rawMileageProjection(protocol, mileage);
  const direction = pickRawNumberField(fields, (key) => key.endsWith('.direction_deg'));
  const altitude = pickRawNumberField(fields, (key) => key.endsWith('.altitude_m'));
  return {
    latitude: latitude.value,
    longitude: longitude.value,
    latitudeKey: latitude.key,
    longitudeKey: longitude.key,
    speedKmh: speed?.value,
    totalMileageKm: mileageProjection?.value,
    totalMileageKey: mileage?.key,
    totalMileageUnitEvidence: mileageProjection?.unitEvidence,
    directionDeg: direction?.value,
    altitudeM: altitude?.value
  };
}

export function rawCoordinateAddressEvidence(
  coordinate: RawCoordinateEvidence | undefined,
  address: RawCoordinateAddressInput
): RawCoordinateAddressEvidence {
  if (!coordinate) {
    return {
      status: 'unavailable',
      label: '无坐标',
      detail: '当前 RAW 没有可用于高德解析的有效经纬度。',
      evidence: 'raw parsed_fields',
      tone: 'waiting'
    };
  }
  if (address.status === 'ready') {
    const provider = address.provider || 'AMap';
    return {
      status: 'ready',
      label: `${provider} 已解析`,
      detail: address.address || '已返回地址',
      evidence: address.region || `${coordinate.latitude.toFixed(6)}, ${coordinate.longitude.toFixed(6)}`,
      tone: address.error ? 'warning' : 'ready'
    };
  }
  if (address.status === 'loading') {
    return {
      status: 'loading',
      label: '解析中',
      detail: '正在根据 RAW 经纬度请求逆地理解析。',
      evidence: `${coordinate.latitude.toFixed(6)}, ${coordinate.longitude.toFixed(6)}`,
      tone: 'waiting'
    };
  }
  if (address.status === 'error') {
    return {
      status: 'error',
      label: '解析失败',
      detail: address.error || '地址解析接口或 AMap Web JS 不可用。',
      evidence: `${coordinate.latitude.toFixed(6)}, ${coordinate.longitude.toFixed(6)}`,
      tone: 'error'
    };
  }
  return {
    status: 'unavailable',
    label: '待解析',
    detail: address.error || '地址解析能力未启用，仍可打开高德坐标。',
    evidence: `${coordinate.latitude.toFixed(6)}, ${coordinate.longitude.toFixed(6)}`,
    tone: 'waiting'
  };
}
