import { computed, onMounted, onUnmounted, ref, shallowRef } from 'vue'
import { listCars, listMissions } from '@/api/projection'
import { fetchFleetHealth } from '@/api/fleetHealth'
import { useProjectionStream } from '@/composables/useProjectionStream'
import type { Car, FleetHealthRow, VehicleCardModel } from '@/types/car'
import type { Mission, MissionStatus } from '@/types/mission'

const CAR_POLL_MS = 5000
const HEALTH_POLL_MS = 20000

function inferMaintenanceMode(car: Car): VehicleCardModel['maintenanceMode'] {
  const s = (car.lstatus ?? '').toLowerCase()
  if (/返厂|blown/.test(s)) return 'blown'
  if (/现场检修|repair/.test(s)) return 'repair'
  if (/下线|offline/.test(s) || car.state === 'offline') return 'offline'
  return 'online'
}

function missionStatusOrder(status: MissionStatus): number {
  if (status === 'running') return 0
  if (status === 'paused') return 1
  if (status === 'assigned') return 2
  return 3
}

function resolveMissionId(car: Car, missions: Mission[]): string | undefined {
  if (car.missionId) {
    const id = String(car.missionId).trim()
    if (id && id !== '0') return id
  }

  const rawKey = car.rawId != null ? String(car.rawId) : undefined
  let best: Mission | undefined

  for (const mission of missions) {
    if (!mission.carId) continue
    if (mission.carId !== car.id && mission.carId !== rawKey) continue
    if (mission.status !== 'running' && mission.status !== 'paused' && mission.status !== 'assigned') {
      continue
    }
    if (!best || missionStatusOrder(mission.status) < missionStatusOrder(best.status)) {
      best = mission
    }
  }

  return best?.id
}

function mergeCarHealth(car: Car, health?: FleetHealthRow, missions: Mission[] = []): VehicleCardModel {
  const missionId = resolveMissionId(car, missions)
  return {
    ...car,
    missionId,
    ip: health?.ip ?? car.ip,
    onboardUrl: health?.onboardUrl ?? car.onboardUrl ?? (car.ip ? `http://${car.ip}:8081` : undefined),
    latencyMs: health?.latencyMs,
    reachable: health?.reachable,
    faultRatePercent: health?.faultRatePercent,
    isAlarmActive: health?.isAlarmActive ?? car.state === 'fault',
    cpuPercent: health?.cpuPercent,
    memPercent: health?.memPercent,
    maintenanceMode: inferMaintenanceMode(car)
  }
}

export function useVehicleHub() {
  const cars = shallowRef<Car[]>([])
  const missions = shallowRef<Mission[]>([])
  const healthRows = shallowRef<FleetHealthRow[]>([])
  const loading = ref(false)
  const healthLoading = ref(false)
  const selectedId = ref<string | null>(null)

  let carTimer: ReturnType<typeof setInterval> | null = null
  let healthTimer: ReturnType<typeof setInterval> | null = null

  const healthByCarId = computed(() => {
    const map = new Map<number, FleetHealthRow>()
    for (const row of healthRows.value) {
      map.set(row.carId, row)
    }
    return map
  })

  const cardModels = computed<VehicleCardModel[]>(() =>
    cars.value.map((car) => {
      const rawId = car.rawId ?? parseInt(car.id.replace(/\D/g, ''), 10)
      const health = Number.isFinite(rawId) ? healthByCarId.value.get(rawId) : undefined
      return mergeCarHealth(car, health, missions.value)
    })
  )

  const totalCount = computed(() => cardModels.value.length)
  const onlineCount = computed(() => cardModels.value.filter((c) => c.state !== 'offline' && c.maintenanceMode === 'online').length)
  const maintenanceCount = computed(() =>
    cardModels.value.filter((c) => c.maintenanceMode === 'offline' || c.maintenanceMode === 'repair' || c.maintenanceMode === 'blown').length
  )
  const alarmCount = computed(() => cardModels.value.filter((c) => c.isAlarmActive).length)
  const unreachableCount = computed(() => cardModels.value.filter((c) => c.reachable === false).length)

  async function loadCars() {
    loading.value = true
    try {
      const [carList, missionList] = await Promise.all([listCars(), listMissions()])
      cars.value = carList
      missions.value = missionList
    } finally {
      loading.value = false
    }
  }

  async function loadHealth() {
    healthLoading.value = true
    try {
      healthRows.value = await fetchFleetHealth()
    } finally {
      healthLoading.value = false
    }
  }

  async function refreshAll() {
    await Promise.all([loadCars(), loadHealth()])
  }

  function patchCarFromStream(rawId: number, patch: Partial<Car>) {
    const idx = cars.value.findIndex((c) => (c.rawId ?? parseInt(c.id.replace(/\D/g, ''), 10)) === rawId)
    if (idx < 0) return
    const next = [...cars.value]
    next[idx] = { ...next[idx], ...patch, lastUpdate: new Date().toISOString() }
    cars.value = next
  }

  const stream = useProjectionStream({
    extraEventKinds: ['alarm', 'car-state'],
    autoConnect: import.meta.env.VITE_USE_MOCK !== 'true'
  })

  stream.on((evt) => {
    if (evt.kind === 'car-state' && evt.payload && typeof evt.payload === 'object') {
      const p = evt.payload as { rawId?: number; id?: string; state?: string; lstatus?: string; missionId?: string }
      const rawId = p.rawId
      if (rawId != null) {
        patchCarFromStream(rawId, {
          state: p.state as Car['state'],
          lstatus: p.lstatus,
          missionId: p.missionId
        })
      }
    }
    if (evt.kind === 'alarm' && evt.payload && typeof evt.payload === 'object') {
      const p = evt.payload as { carId?: number; action?: string }
      if (p.carId != null) {
        const isActive = p.action === 'raise' || p.action === 'update'
        const idx = healthRows.value.findIndex((r) => r.carId === p.carId)
        if (idx >= 0) {
          const next = [...healthRows.value]
          next[idx] = { ...next[idx], isAlarmActive: isActive }
          healthRows.value = next
        }
        patchCarFromStream(p.carId, { state: isActive ? 'fault' : undefined })
      }
    }
  })

  onMounted(() => {
    void refreshAll()
    carTimer = setInterval(() => void loadCars(), CAR_POLL_MS)
    healthTimer = setInterval(() => void loadHealth(), HEALTH_POLL_MS)
  })

  onUnmounted(() => {
    if (carTimer) clearInterval(carTimer)
    if (healthTimer) clearInterval(healthTimer)
    stream.disconnect()
  })

  return {
    cardModels,
    loading,
    healthLoading,
    selectedId,
    totalCount,
    onlineCount,
    maintenanceCount,
    alarmCount,
    unreachableCount,
    refreshAll,
    loadCars,
    loadHealth
  }
}
