<template>
  <div v-if="visible" class="vehicle-edit-mask" @click.self="handleClose">
    <div class="vehicle-edit-dialog">
      <div class="dialog-header">
        <span class="dialog-title">运行对象编辑</span>
        <img class="dialog-close" :src="closeIcon" alt="close" @click="handleClose" />
      </div>

      <div class="dialog-body">
        <div class="search-row">
          <span class="search-label">对象检索：</span>
          <input
            v-model="searchText"
            class="search-input"
            placeholder="请输入航班号/车牌号"
            @keyup.enter="handleSearch"
          />
        </div>

        <div class="table-header">
          <div class="col col-enable">启动</div>
          <div class="col col-id">航班号/车牌号</div>
          <div class="col col-type">类型</div>
          <div class="col col-route">路线</div>
        </div>

        <div class="table-body">
          <div v-if="loading" class="table-empty">加载中...</div>
          <div v-else-if="filteredRows.length === 0" class="table-empty">暂无数据</div>
          <div v-else class="table-rows">
            <div v-for="row in filteredRows" :key="row.id" class="table-row">
              <div class="col col-enable">
                <label class="checkbox-container">
                  <input type="checkbox" v-model="row.enabled" />
                  <span class="checkmark"></span>
                </label>
              </div>
              <div class="col col-id">
                <div class="cell-box">{{ row.id }}</div>
              </div>
              <div class="col col-type">
                <select v-model="row.typeSelected" class="type-select">
                  <option v-for="opt in selectableTypeOptions" :key="opt.value" :value="opt.value">
                    {{ opt.label }}
                  </option>
                </select>
              </div>
              <div class="col col-route">
                <select v-model="row.routeName" class="type-select">
                  <option value="">未选择</option>
                  <option v-for="r in routeOptions" :key="r.routeName" :value="r.routeName">
                    {{ r.label }}
                  </option>
                </select>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="dialog-footer">
        <button class="footer-btn cancel" :disabled="submitting" @click="handleClose">取消</button>
        <button class="footer-btn confirm" :disabled="submitting" @click="handleConfirm">
          {{ submitting ? '提交中...' : '确定' }}
        </button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import useVehicleDisplayStore from '@/store/modules/vehicleDisplay'
import { assignVehicleRoute, syncVehicleRegistry } from '@/api/platform/runtimeConfig'
import closeIcon from '@/assets/images/close_icon.png'
import { createWebSocket } from '@/utils/websocket'

const props = defineProps({
  visible: { type: Boolean, default: false }
})

const emit = defineEmits(['close'])

const vehicleDisplayStore = useVehicleDisplayStore()

const loading = ref(false)
const submitting = ref(false)
const searchText = ref('')
const rows = ref([])
let wsService = null
let wsMessageHandler = null
let loadingTimer = null
const selectableTypeOptions = [
  { label: '航空器', value: 'AIRCRAFT' },
  { label: '无人车', value: 'UNMANNED_VEHICLE' },
  { label: '特勤车', value: 'SPECIAL_VEHICLE' }
]
const routeOptions = [
  {
    label: '807-805',
    routeName: '807-805',
    description: '测试路线-807-805',
    points: [
      { lon: 40508513.641064, lat: 4024186.813497 },
      { lon: 40508714.127776, lat: 4024250.934516 },
      { lon: 40508853.166318, lat: 4024293.929307 },
      { lon: 40508966.275693, lat: 4024330.441807 }
    ]
  },
  {
    label: 'M4 829-826-K1',
    routeName: 'M4 829-826-K1',
    description: '测试路线-M4 829-826-K1',
    points: [
      { lon: 40507849.913313, lat: 4023625.932486 },
      { lon: 40507732.597485, lat: 4023991.671027 },
      { lon: 40507723.998527, lat: 4023986.908527 },
      { lon: 40507674.841898, lat: 4024138.30738 }
    ]
  },
  {
    label: 'M1 K2-1-1-1#消防',
    routeName: 'M1 K2-1-1-1#消防',
    description: '测试路线-M1 K2-1-1-1#消防',
    points: [
      { lon: 40509113.197805, lat: 4024029.951692 },
      { lon: 40508997.734226, lat: 4024393.687528 },
      { lon: 40509007.523809, lat: 4024395.275028 },
      { lon: 40508957.783071, lat: 4024548.361738 }
    ]
  }
]

const filteredRows = computed(() => {
  const keyword = (searchText.value || '').trim().toLowerCase()
  if (!keyword) return rows.value
  return rows.value.filter((r) => String(r?.id || '').toLowerCase().includes(keyword))
})

function handleSearch() {
  searchText.value = (searchText.value || '').trim()
}

function parseWsMessage(raw) {
  if (!raw) return null
  if (typeof raw === 'object') return raw
  if (typeof raw !== 'string') return null
  try {
    return JSON.parse(raw)
  } catch (e) {
    return null
  }
}

function mapObjectTypeToLabel(objectType) {
  const t = String(objectType || '').toUpperCase()
  if (t === 'UNMANNED_VEHICLE') return '无人车'
  if (t === 'SPECIAL_VEHICLE') return '特勤车'
  if (t === 'AIRCRAFT') return '航空器'
  if (t === 'WUREN') return '无人车'
  if (t === 'TEQIN') return '特勤车'
  if (t === 'AIRCRAFT' || t === 'AIRCRAFT_IN' || t === 'AIRCRAFT_OUT' || t === 'HANGKONG') return '航空器'
  if (!t) return '未知'
  return t
}

function normalizeTypeForSelection(objectType) {
  const t = String(objectType || '').toUpperCase()
  if (t === 'UNMANNED_VEHICLE' || t === 'WUREN') return 'UNMANNED_VEHICLE'
  if (t === 'SPECIAL_VEHICLE' || t === 'TEQIN') return 'SPECIAL_VEHICLE'
  if (t === 'AIRCRAFT' || t === 'HANGKONG' || t === 'AIRCRAFT_IN' || t === 'AIRCRAFT_OUT') return 'AIRCRAFT'
  return 'AIRCRAFT'
}

function mapObjectTypeToRegistryType(objectType) {
  const t = String(objectType || '').toUpperCase()
  if (t === 'UNMANNED_VEHICLE') return 'WUREN'
  if (t === 'SPECIAL_VEHICLE') return 'TEQIN'
  if (t === 'AIRCRAFT') return 'HANGKONG'
  if (t === 'WUREN') return 'WUREN'
  if (t === 'TEQIN') return 'TEQIN'
  if (t === 'AIRCRAFT' || t === 'AIRCRAFT_IN' || t === 'AIRCRAFT_OUT' || t === 'HANGKONG') return 'HANGKONG'
  if (t === 'JIUYUAN') return 'JIUYUAN'
  return 'PUTONG'
}

function mapObjectTypeToAssignmentVehicleType(objectType) {
  const t = String(objectType || '').toUpperCase()
  if (t === 'UNMANNED_VEHICLE' || t === 'WUREN') return 'UNMANNED_VEHICLE'
  if (t === 'SPECIAL_VEHICLE' || t === 'TEQIN') return 'SPECIAL_VEHICLE'
  return ''
}

function upsertVehicleRow(vehicleId, objectType) {
  const id = String(vehicleId || '').trim()
  if (!id) return

  const mappedType = mapObjectTypeToLabel(objectType)
  const rawType = String(objectType || '').trim()
  const savedRoute = vehicleDisplayStore.getVehicleRouteAssignment(id)

  const existing = rows.value.find((r) => r?.id === id)
  if (existing) {
    existing.lastSeen = Date.now()
    if (rawType) existing.objectType = rawType
    if (!existing.typeSelected) {
      const override = vehicleDisplayStore.getVehicleTypeOverride(id)
      existing.typeSelected = override || normalizeTypeForSelection(rawType)
    }
    if (!existing.routeName && savedRoute) existing.routeName = savedRoute
    return
  }

  const enabled = vehicleDisplayStore.isVehicleEnabled(id)
  const override = vehicleDisplayStore.getVehicleTypeOverride(id)
  rows.value = [
    ...rows.value,
    {
      id,
      enabled,
      objectType: rawType,
      typeSelected: override || normalizeTypeForSelection(rawType),
      routeName: savedRoute || '',
      lastSeen: Date.now()
    }
  ]
}

function startWebSocketFeed() {
  const wsUrl = window.APP_CONFIG?.WS_BASE_URL
  if (!wsUrl) {
    loading.value = false
    return
  }

  wsService = createWebSocket(wsUrl, {
    reconnectInterval: 3000,
    maxReconnectAttempts: 5
  })

  wsMessageHandler = (raw) => {
    const data = parseWsMessage(raw)
    if (!data || data.type !== 'position_update') return
    const payload = data.payload || {}
    upsertVehicleRow(payload.object_id, payload.object_type)
    if (loading.value) loading.value = false
  }

  wsService.on('message', wsMessageHandler)

  wsService.send(
    JSON.stringify({
      type: 'subscribe',
      topics: ['position_update', 'collision_warning', 'rule_violation'],
      timestamp: Date.now()
    })
  )

  if (loadingTimer) clearTimeout(loadingTimer)
  loadingTimer = setTimeout(() => {
    loading.value = false
  }, 1200)
}

function stopWebSocketFeed() {
  if (loadingTimer) {
    clearTimeout(loadingTimer)
    loadingTimer = null
  }
  if (wsService && wsMessageHandler) {
    wsService.off('message', wsMessageHandler)
  }
  wsMessageHandler = null
  wsService = null
}

function handleClose() {
  if (submitting.value) return
  emit('close')
}

async function handleConfirm() {
  if (submitting.value) return

  submitting.value = true
  try {
    const enabledPayload = (rows.value || [])
      .filter((r) => !!r?.id && r.enabled === true)
      .map((r) => ({
        vehicleID: String(r.id),
        vehicleType: mapObjectTypeToRegistryType(r.typeSelected || r.objectType)
      }))

    const disabledPayload = (rows.value || [])
      .filter((r) => !!r?.id && r.enabled !== true && vehicleDisplayStore.isVehicleEnabled(r.id))
      .map((r) => ({
        vehicleID: String(r.id),
        vehicleType: 'PUTONG'
      }))

    const payload = [...enabledPayload, ...disabledPayload]
    if (payload.length) {
      await syncVehicleRegistry(payload)
    }

    const assignments = (rows.value || [])
      .filter((r) => !!r?.id && r.enabled === true && !!r.routeName)
      .map((r) => {
        const opt = routeOptions.find((o) => o.routeName === r.routeName)
        const vehicleType = mapObjectTypeToAssignmentVehicleType(r.typeSelected || r.objectType)
        if (!opt || !vehicleType) return null
        return {
          vehicleID: String(r.id),
          vehicleType,
          routeName: opt.routeName,
          description: opt.description,
          status: 'ACTIVE',
          isBidirectional: false,
          maxSpeedKph: 25.0,
          typicalSpeedKph: 15.0,
          points: opt.points,
          route: { points: opt.points }
        }
      })
      .filter(Boolean)

    if (assignments.length) {
      await Promise.all(assignments.map((a) => assignVehicleRoute(a)))
    }

    ;(rows.value || []).forEach((r) => {
      if (!r?.id) return
      vehicleDisplayStore.setVehicleTypeOverride(r.id, r.typeSelected || normalizeTypeForSelection(r.objectType))
      vehicleDisplayStore.setVehicleRouteAssignment(r.id, r.routeName)
      vehicleDisplayStore.setVehicleEnabled(r.id, r.enabled === true)
    })

    ElMessage.success('已同步到后端')
    emit('close')
  } catch (e) {
    ElMessage.error(e?.message || '同步失败')
  } finally {
    submitting.value = false
  }
}

watch(
  () => props.visible,
  async (v) => {
    if (!v) {
      stopWebSocketFeed()
      return
    }
    searchText.value = ''
    rows.value = []
    loading.value = true
    startWebSocketFeed()
  },
  { immediate: false }
)
</script>

<style scoped>
.vehicle-edit-mask {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 4000;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
}

.vehicle-edit-dialog {
  width: 900px;
  max-width: calc(100vw - 40px);
  background-color: #424851;
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  overflow: hidden;
  color: #ffffff;
}

.dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid #303850;
}

.dialog-title {
  font-size: 18px;
  font-weight: 600;
}

.dialog-close {
  width: 22px;
  height: 22px;
  cursor: pointer;
}

.dialog-body {
  padding: 14px 18px 10px;
}

.search-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

.search-label {
  font-size: 14px;
  color: #dcdcdc;
  white-space: nowrap;
}

.search-input {
  flex: 0 0 320px;
  height: 34px;
  border-radius: 4px;
  border: 1px solid #2f7ab9;
  outline: none;
  background: rgba(0, 150, 255, 0.08);
  color: #ffffff;
  padding: 0 12px;
}

.search-input::placeholder {
  color: rgba(255, 255, 255, 0.6);
}

.table-header {
  display: grid;
  grid-template-columns: 90px 1fr 140px 240px;
  align-items: center;
  height: 40px;
  padding: 0 10px;
  border: 1px solid #303850;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.12);
  font-size: 14px;
}

.table-body {
  margin-top: 10px;
  border: 1px solid #303850;
  border-radius: 6px;
  overflow: hidden;
}

.table-empty {
  padding: 30px 0;
  text-align: center;
  color: rgba(255, 255, 255, 0.7);
}

.table-rows {
  max-height: 420px;
  overflow: auto;
}

.table-row {
  display: grid;
  grid-template-columns: 90px 1fr 140px 240px;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border-bottom: 1px solid rgba(48, 56, 80, 0.9);
}

.table-row:last-child {
  border-bottom: none;
}

.cell-box {
  height: 34px;
  display: flex;
  align-items: center;
  padding: 0 12px;
  border-radius: 4px;
  border: 1px solid rgba(47, 122, 185, 0.8);
  background: rgba(0, 150, 255, 0.08);
  color: #ffffff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.type-select {
  width: 100%;
  height: 34px;
  border-radius: 4px;
  border: 1px solid rgba(47, 122, 185, 0.8);
  outline: none;
  background: rgba(0, 150, 255, 0.08);
  color: #ffffff;
  padding: 0 12px;
  appearance: none;
}

.type-select option {
  background: #424851;
  color: #ffffff;
}

.dialog-footer {
  padding: 12px 18px 16px;
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  border-top: 1px solid #303850;
}

.footer-btn {
  width: 88px;
  height: 34px;
  border-radius: 4px;
  cursor: pointer;
  border: 1px solid rgba(47, 122, 185, 0.8);
  background: rgba(0, 150, 255, 0.08);
  color: #ffffff;
}

.footer-btn.confirm {
  background: #0096ff;
  border-color: #0078cc;
}

.checkbox-container {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  position: relative;
  user-select: none;
  padding-left: 22px;
}

.checkbox-container input {
  position: absolute;
  opacity: 0;
  cursor: pointer;
  height: 0;
  width: 0;
}

.checkmark {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 16px;
  width: 16px;
  border: 1px solid #999999;
  border-radius: 3px;
  background-color: transparent;
}

.checkbox-container input:checked ~ .checkmark {
  background-color: #0096ff;
  border-color: #0078cc;
}

.checkmark:after {
  content: "";
  position: absolute;
  display: none;
}

.checkbox-container input:checked ~ .checkmark:after {
  display: block;
}

.checkbox-container .checkmark:after {
  left: 5px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid white;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.table-rows::-webkit-scrollbar {
  width: 6px;
}

.table-rows::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.06);
}

.table-rows::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.25);
  border-radius: 3px;
}
</style>
