<template>
  <div class="vehicle-monitor" :class="{ 'is-compact': compact, 'is-table': table }">
    <div v-if="!compact && !table" class="overview-row">
      <div class="overview-item">
        <div class="overview-num">{{ cars.length }}</div>
        <div class="overview-label">总数</div>
      </div>
      <div class="overview-item">
        <div class="overview-num online">{{ onlineCount }}</div>
        <div class="overview-label">在线</div>
      </div>
      <div class="overview-item">
        <div class="overview-num running">{{ runningCount }}</div>
        <div class="overview-label">运行</div>
      </div>
      <div class="overview-item">
        <div class="overview-num charging">{{ chargingCount }}</div>
        <div class="overview-label">充电</div>
      </div>
      <div class="overview-item">
        <div class="overview-num fault">{{ faultCount }}</div>
        <div class="overview-label">故障</div>
      </div>
    </div>

    <div class="toolbar">
      <el-input
        v-model="search"
        size="small"
        clearable
        :placeholder="table ? '搜索车辆编号/名称' : '搜索 ID / 名称 / 任务'"
        class="search"
      />
      <el-select
        v-if="!table"
        v-model="filterState"
        size="small"
        placeholder="状态"
        clearable
        class="filter"
      >
        <el-option
          v-for="opt in stateOptions"
          :key="opt.value"
          :label="opt.label"
          :value="opt.value"
        />
      </el-select>
    </div>

    <div v-if="table" class="chip-row" role="tablist" aria-label="状态筛选">
      <button
        v-for="chip in filterChips"
        :key="chip.key"
        type="button"
        role="tab"
        class="chip"
        :class="{ 'is-active': quickFilter === chip.key }"
        :aria-selected="quickFilter === chip.key"
        @click="quickFilter = chip.key"
      >
        {{ chip.label }}
        <span class="chip-n">{{ chip.count }}</span>
      </button>
    </div>

    <div v-if="table" class="table-wrap">
      <div class="table-head" aria-hidden="true">
        <span class="col-id">车辆编号</span>
        <span class="col-state">状态</span>
        <span class="col-bat">电量</span>
        <span class="col-pos">当前位置</span>
      </div>
      <div class="vehicle-list table-body">
        <button
          v-for="car in filteredCars"
          :key="car.id"
          type="button"
          class="table-row"
          :class="{ 'is-selected': car.id === selectedId }"
          @click="onSelect(car)"
        >
          <span class="col-id" :title="car.name">{{ shortId(car) }}</span>
          <span class="col-state">
            <span class="state-dot" :class="`dot-${car.state}`" />
            {{ stateLabel(car.state) }}
          </span>
          <span class="col-bat" :class="batteryLevel(batteryPct(car))">{{ batteryText(car) }}</span>
          <span class="col-pos" :title="positionText(car)">{{ positionText(car) }}</span>
        </button>
        <div v-if="!filteredCars.length" class="empty muted">无匹配车辆</div>
      </div>
    </div>

    <div v-else class="vehicle-list">
      <div
        v-for="car in filteredCars"
        :key="car.id"
        class="vehicle-row"
        :class="{ 'is-selected': car.id === selectedId }"
        @click="onSelect(car)"
      >
        <div class="vehicle-head">
          <span class="vid">{{ car.id }}</span>
          <span class="vname" :title="car.name">{{ car.name }}</span>
          <el-tag
            size="small"
            :type="stateTagType(car.state)"
            class="state-tag"
            effect="dark"
          >
            <span class="dot" :class="`dot-${car.state}`" />
            {{ stateLabel(car.state) }}
          </el-tag>
        </div>

        <div class="vehicle-sub">
          <div class="battery-mini" :title="`电量 ${batteryPct(car)}%`">
            <el-progress
              :percentage="batteryPct(car)"
              :stroke-width="6"
              :show-text="false"
              :color="batteryColor(batteryPct(car))"
              class="battery-bar"
            />
            <span class="battery-text" :class="batteryLevel(batteryPct(car))">
              {{ batteryPct(car) }}%
            </span>
          </div>
          <div class="mission-mini">
            <template v-if="missionForCar(car)">
              <el-tag
                size="small"
                :type="missionStatusTagType(missionForCar(car)!.status)"
                effect="plain"
                class="mission-tag"
              >
                {{ missionStatusLabel(missionForCar(car)!.status) }}
              </el-tag>
              <span class="mission-name" :title="missionForCar(car)!.name">
                {{ missionForCar(car)!.name }}
              </span>
            </template>
            <template v-else>
              <span class="mission-name muted">空闲</span>
            </template>
          </div>
        </div>
      </div>

      <div v-if="!filteredCars.length" class="empty muted">
        无匹配车辆
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import type { Car, CarState } from '@/types/car'
import type { Mission, MissionStatus } from '@/types/mission'
import type { SelectedObjectRef } from '@/types/workbench'

const props = defineProps<{
  cars: Car[]
  missions: Mission[]
  selectedId?: string | null
  /** 紧凑模式：隐藏顶部概览条 */
  compact?: boolean
  /** 表格模式：筛选芯片 + 四列表格（地图监控参考布局） */
  table?: boolean
}>()

const emit = defineEmits<{
  select: [ref: SelectedObjectRef]
}>()

const search = ref('')
const filterState = ref<CarState | ''>('')
type QuickFilter = 'all' | 'running' | 'idle' | 'offline' | 'fault'
const quickFilter = ref<QuickFilter>('all')

const stateOptions: { value: CarState; label: string }[] = [
  { value: 'idle', label: '空闲' },
  { value: 'running', label: '运行中' },
  { value: 'charging', label: '充电中' },
  { value: 'paused', label: '已暂停' },
  { value: 'fault', label: '故障' },
  { value: 'offline', label: '离线' }
]

const stateLabels = stateOptions.reduce<Record<string, string>>((acc, o) => {
  acc[o.value] = o.label
  return acc
}, {})

function stateLabel(s: CarState): string {
  return stateLabels[s] ?? s
}

type TagType = 'success' | 'warning' | 'danger' | 'info' | 'primary'

function stateTagType(s: CarState): TagType {
  switch (s) {
    case 'running':
      return 'success'
    case 'charging':
      return 'primary'
    case 'paused':
      return 'warning'
    case 'fault':
      return 'danger'
    case 'offline':
      return 'info'
    case 'idle':
    default:
      return 'info'
  }
}

const missionStatusLabels: Record<MissionStatus, string> = {
  queued: '排队',
  assigned: '已分配',
  running: '执行中',
  paused: '暂停',
  completed: '已完成',
  cancelled: '已取消',
  failed: '失败'
}

function missionStatusLabel(s: MissionStatus): string {
  return missionStatusLabels[s] ?? s
}

function missionStatusTagType(s: MissionStatus): TagType {
  switch (s) {
    case 'running':
      return 'success'
    case 'assigned':
      return 'primary'
    case 'queued':
      return 'info'
    case 'paused':
      return 'warning'
    case 'completed':
      return 'success'
    case 'cancelled':
      return 'info'
    case 'failed':
      return 'danger'
    default:
      return 'info'
  }
}

const onlineCount = computed(() => props.cars.filter((c) => c.state !== 'offline').length)
const runningCount = computed(() => props.cars.filter((c) => c.state === 'running').length)
const chargingCount = computed(() => props.cars.filter((c) => c.state === 'charging').length)
const faultCount = computed(() => props.cars.filter((c) => c.state === 'fault').length)
const idleCount = computed(() => props.cars.filter((c) => c.state === 'idle').length)
const offlineCount = computed(() => props.cars.filter((c) => c.state === 'offline').length)

const filterChips = computed(() => [
  { key: 'all' as const, label: '全部', count: props.cars.length },
  { key: 'running' as const, label: '运行中', count: runningCount.value },
  { key: 'idle' as const, label: '空闲', count: idleCount.value },
  { key: 'offline' as const, label: '离线', count: offlineCount.value },
  { key: 'fault' as const, label: '异常', count: faultCount.value }
])

const missionByCarId = computed(() => {
  const order = (s: MissionStatus) =>
    s === 'running' ? 0 : s === 'paused' ? 1 : s === 'assigned' ? 2 : 3
  const map = new Map<string, Mission>()
  for (const m of props.missions) {
    if (!m.carId) continue
    if (m.status !== 'running' && m.status !== 'paused' && m.status !== 'assigned') continue
    const prev = map.get(m.carId)
    if (!prev || order(m.status) < order(prev.status)) {
      map.set(m.carId, m)
    }
  }
  return map
})

function missionForCar(car: Car): Mission | undefined {
  if (car.missionId) {
    const found = props.missions.find((m) => m.id === car.missionId)
    if (found) return found
  }
  return missionByCarId.value.get(car.id)
}

function batteryPct(car: Car): number {
  const raw = car.batterySoc ?? 0
  if (!raw) return 0
  const pct = raw > 1 ? raw : raw * 100
  return Math.max(0, Math.min(100, Math.round(pct)))
}

function batteryText(car: Car): string {
  const pct = batteryPct(car)
  return pct > 0 ? `${pct}%` : '—'
}

function batteryColor(p: number): string {
  if (p < 20) return '#f56c6c'
  if (p < 50) return '#e6a23c'
  return '#67c23a'
}

function batteryLevel(p: number): 'low' | 'mid' | 'high' {
  if (p < 20) return 'low'
  if (p < 50) return 'mid'
  return 'high'
}

function shortId(car: Car): string {
  if (car.rawId != null) return String(car.rawId).padStart(3, '0').slice(-3)
  const digits = car.id.replace(/\D/g, '')
  return digits ? digits.slice(-3) : car.id
}

function positionText(car: Car): string {
  if (!Number.isFinite(car.x) || !Number.isFinite(car.y)) return '-'
  return `${Math.round(car.x)}, ${Math.round(car.y)}`
}

const filteredCars = computed(() => {
  const q = search.value.trim().toLowerCase()
  const tokens = q ? q.split(/\s+/).filter(Boolean) : []
  return props.cars.filter((c) => {
    if (props.table) {
      if (quickFilter.value === 'running' && c.state !== 'running') return false
      if (quickFilter.value === 'idle' && c.state !== 'idle') return false
      if (quickFilter.value === 'offline' && c.state !== 'offline') return false
      if (quickFilter.value === 'fault' && c.state !== 'fault') return false
    } else if (filterState.value && c.state !== filterState.value) {
      return false
    }
    if (!tokens.length) return true
    const mission = missionForCar(c)
    const hay = [
      c.id,
      c.name,
      c.typeName ?? '',
      c.group ?? '',
      c.ip ?? '',
      stateLabel(c.state),
      mission?.name ?? '',
      mission ? missionStatusLabel(mission.status) : '',
      positionText(c)
    ]
      .join(' ')
      .toLowerCase()
    return tokens.every((t) => hay.includes(t))
  })
})

function onSelect(car: Car) {
  emit('select', { kind: 'vehicle', id: detailIdForCar(car), name: car.name })
}

function detailIdForCar(car: Car): string {
  if (car.rawId != null) return String(car.rawId)
  return car.id.replace(/^C/i, '').replace(/^0+/, '') || car.id
}
</script>

<style scoped>
.vehicle-monitor {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
  height: 100%;
  overflow: hidden;
}
.vehicle-monitor.is-compact { gap: 8px; }
.vehicle-monitor.is-table { gap: 8px; }

.vehicle-monitor.is-compact .vehicle-row {
  border-radius: 8px;
  border-color: transparent;
  background: transparent;
  padding: 8px 10px;
}
.vehicle-monitor.is-compact .vehicle-row:hover {
  background: var(--mg-veil-2);
  border-color: transparent;
}
.vehicle-monitor.is-compact .vehicle-row.is-selected {
  background: rgba(var(--mg-primary-rgb), 0.1);
  border-color: transparent;
  box-shadow: inset 3px 0 0 var(--mg-primary);
}

.overview-row {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  flex: none;
}
.overview-item {
  background: var(--mg-veil-1);
  border: 1px solid var(--mg-veil-border);
  border-radius: 6px;
  padding: 4px 2px;
  text-align: center;
  transition: var(--mg-transition, all 0.2s ease);
}
.overview-item:hover {
  background: rgba(var(--mg-accent-rgb, 142, 200, 252), 0.14);
  border-color: rgba(var(--mg-accent-rgb, 142, 200, 252), 0.4);
}
.overview-num {
  font-size: 15px;
  font-weight: 600;
  color: var(--mg-text-light);
  line-height: 1.2;
}
.overview-num.online { color: var(--mg-accent); }
.overview-num.running { color: var(--mg-status-success); }
.overview-num.charging { color: var(--mg-primary-hover); }
.overview-num.fault { color: var(--mg-status-danger); }
.overview-label {
  font-size: 11px;
  color: var(--mg-text-muted);
  margin-top: 2px;
}

.toolbar {
  display: flex;
  gap: 6px;
  flex: none;
}
.toolbar .search { flex: 1; min-width: 0; }
.toolbar .filter { width: 100px; flex: none; }

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex: none;
}
.chip {
  appearance: none;
  border: 1px solid var(--mg-veil-border);
  background: transparent;
  color: var(--mg-text-muted);
  font-size: 11px;
  font-weight: 550;
  height: 26px;
  padding: 0 8px;
  border-radius: 6px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.chip:hover {
  color: var(--mg-text-light);
  border-color: var(--mg-veil-border-hi);
}
.chip.is-active {
  background: rgba(var(--mg-primary-rgb), 0.12);
  border-color: rgba(var(--mg-primary-rgb), 0.45);
  color: var(--mg-primary);
}
.chip-n {
  font-family: var(--mg-font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.table-wrap {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.table-head,
.table-row {
  display: grid;
  grid-template-columns: 56px 64px 48px minmax(0, 1fr);
  gap: 6px;
  align-items: center;
  padding: 0 8px;
}
.table-head {
  flex: none;
  height: 28px;
  font-size: 11px;
  font-weight: 600;
  color: var(--mg-text-muted);
  border-bottom: 1px solid var(--mg-veil-border);
}
.table-body {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  gap: 0;
  padding-right: 0;
}
.table-row {
  appearance: none;
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--mg-veil-border);
  background: transparent;
  color: var(--mg-text-light);
  text-align: left;
  height: 40px;
  font-size: 12px;
  cursor: pointer;
  transition: background 0.15s ease;
}
.table-row:hover {
  background: var(--mg-veil-1);
}
.table-row.is-selected {
  background: rgba(var(--mg-primary-rgb), 0.1);
  box-shadow: inset 3px 0 0 var(--mg-primary);
}
.col-id {
  font-family: var(--mg-font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 650;
  font-size: 12px;
}
.col-state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  color: var(--mg-text-muted);
  white-space: nowrap;
}
.col-bat {
  font-family: var(--mg-font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  font-weight: 600;
}
.col-bat.low { color: var(--mg-status-danger); }
.col-bat.mid { color: var(--mg-status-warning); }
.col-bat.high { color: var(--mg-status-success); }
.col-pos {
  font-size: 11px;
  color: var(--mg-text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.state-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex: none;
  background: currentColor;
}
.state-dot.dot-running,
.dot.dot-running { color: var(--mg-status-success); background: var(--mg-status-success); }
.state-dot.dot-idle,
.dot.dot-idle { color: var(--mg-status-info); background: var(--mg-status-info); }
.state-dot.dot-offline,
.dot.dot-offline { color: var(--mg-text-faint); background: var(--mg-text-faint); }
.state-dot.dot-fault,
.dot.dot-fault { color: var(--mg-status-danger); background: var(--mg-status-danger); }
.state-dot.dot-charging,
.dot.dot-charging { color: var(--mg-primary); background: var(--mg-primary); }
.state-dot.dot-paused,
.dot.dot-paused { color: var(--mg-status-warning); background: var(--mg-status-warning); }

.vehicle-list {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-right: 2px;
}

.vehicle-row {
  background: var(--mg-veil-1);
  border: 1px solid var(--mg-veil-border);
  border-radius: 4px;
  padding: 4px 6px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: none;
  transition: all 0.18s ease;
}
.vehicle-row:hover {
  background: rgba(var(--mg-accent-rgb, 142, 200, 252), 0.12);
  border-color: rgba(var(--mg-accent-rgb, 142, 200, 252), 0.35);
}
.vehicle-row.is-selected {
  background: rgba(109, 40, 217, 0.32);
  border-color: rgba(167, 139, 250, 0.75);
  box-shadow: inset 3px 0 0 rgba(196, 181, 253, 0.95);
}

.vehicle-head {
  display: flex;
  align-items: center;
  gap: 6px;
}
.vid {
  font-size: 10.5px;
  color: var(--mg-text-muted);
  font-family: ui-monospace, 'SFMono-Regular', 'Menlo', monospace;
  flex: none;
}
.vname {
  flex: 1;
  min-width: 0;
  color: var(--mg-text-light);
  font-weight: 600;
  font-size: 11.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.state-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex: none;
}
.dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.dot-running { color: #6fcd45; }
.dot-charging { color: var(--mg-primary-hover); }
.dot-paused { color: #e6a23c; }
.dot-fault { color: #ff7396; }
.dot-offline { color: var(--mg-text-faint); }
.dot-idle { color: var(--mg-accent); }

.vehicle-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10.5px;
}
.battery-mini {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 44%;
  min-width: 0;
}
.mission-mini {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.battery-bar {
  flex: 1;
  min-width: 0;
}
.battery-bar :deep(.el-progress-bar__outer) {
  background: var(--mg-veil-3);
}
.battery-text {
  width: 34px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 11.5px;
  flex: none;
}
.battery-text.low { color: var(--mg-status-danger); }
.battery-text.mid { color: var(--mg-status-warning); }
.battery-text.high { color: var(--mg-status-success); }

.mission-name {
  flex: 1;
  min-width: 0;
  color: var(--mg-text-light);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mission-name.muted { color: var(--mg-text-dim); }
.mission-tag { flex: none; }

.empty {
  text-align: center;
  padding: 24px 0;
  font-size: 12px;
}
.muted { color: var(--mg-text-muted); }
</style>
