<template>
  <div class="ota-packages">
    <div class="toolbar">
      <el-select v-model="pullCarId" size="small" filterable clearable placeholder="从车辆拉取" class="car-select">
        <el-option v-for="c in cars" :key="c.id" :label="`${c.name} (${c.ip || '无IP'})`" :value="c.id" />
      </el-select>
      <el-button size="small" type="primary" :disabled="!canWrite || !pullCarId" :loading="pulling" @click="onPull">
        拉取
      </el-button>
      <el-upload :show-file-list="false" :disabled="!canWrite" :http-request="onUpload" accept=".zip,.exe,.dll">
        <el-button size="small" :disabled="!canWrite" :loading="uploading">本地上传</el-button>
      </el-upload>
      <el-button size="small" :icon="Refresh" :loading="loading" @click="reload" />
    </div>

    <div class="split">
      <el-table
        v-loading="loading"
        :data="packages"
        size="small"
        height="400"
        highlight-current-row
        @current-change="onCurrent"
      >
        <el-table-column label="包 ID" min-width="180">
          <template #default="{ row }">
            <span class="mono">{{ row.id }}</span>
            <el-tag v-if="row.isTarget" size="small" type="success" class="tag">目标</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="sourceIp" label="来源" width="110" />
        <el-table-column label="大小" width="90">
          <template #default="{ row }">{{ formatBytes(row.totalBytes) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="160" fixed="right">
          <template #default="{ row }">
            <el-button link type="primary" size="small" :disabled="!canWrite || row.isTarget" @click="onActivate(row)">
              设为目标
            </el-button>
            <el-button link type="danger" size="small" :disabled="!canWrite || row.isTarget" @click="onDelete(row)">
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <div class="detail">
        <h4>组件明细</h4>
        <el-empty v-if="!current" description="选择一个版本包" :image-size="64" />
        <ul v-else>
          <li v-for="(art, key) in current.components" :key="key">
            <span class="key">{{ key }}</span>
            <span class="mono">{{ art.hash?.slice(0, 12) }}</span>
            <span class="dim">{{ formatBytes(art.size) }}</span>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { Refresh } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { UploadRequestOptions } from 'element-plus'
import {
  activateOtaPackage,
  deleteOtaPackage,
  listOtaPackages,
  listOtaVehicles,
  pullOtaPackage,
  uploadOtaPackage
} from '@/api/ota'
import type { OtaPackageInfo, OtaVehicleRow } from '@/types/ota'

defineProps<{ canWrite: boolean }>()
const emit = defineEmits<{ changed: [] }>()

const packages = ref<OtaPackageInfo[]>([])
const cars = ref<OtaVehicleRow[]>([])
const current = ref<OtaPackageInfo | null>(null)
const pullCarId = ref('')
const loading = ref(false)
const pulling = ref(false)
const uploading = ref(false)

function formatBytes(n: number) {
  if (!n) return '0 B'
  if (n < 1024) return `${n} B`
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`
  return `${(n / 1024 / 1024).toFixed(1)} MB`
}

async function reload() {
  loading.value = true
  try {
    packages.value = await listOtaPackages()
    cars.value = await listOtaVehicles(false)
    if (current.value) {
      current.value = packages.value.find((p) => p.id === current.value!.id) || null
    }
  } catch (e: any) {
    ElMessage.error(e?.message || '加载版本库失败')
  } finally {
    loading.value = false
  }
}

function onCurrent(row: OtaPackageInfo | null) {
  current.value = row
}

async function onPull() {
  if (!pullCarId.value) return
  pulling.value = true
  try {
    const pkg = await pullOtaPackage(pullCarId.value)
    ElMessage.success(pkg.components && Object.keys(pkg.components).length ? '拉取完成' : '拉取结束，但未收到文件')
    emit('changed')
    await reload()
  } catch (e: any) {
    ElMessage.error(e?.message || '拉取失败')
  } finally {
    pulling.value = false
  }
}

async function onUpload(opt: UploadRequestOptions) {
  uploading.value = true
  try {
    await uploadOtaPackage(opt.file as File)
    ElMessage.success('上传完成')
    emit('changed')
    await reload()
    opt.onSuccess?.({})
  } catch (e: any) {
    ElMessage.error(e?.message || '上传失败')
    opt.onError?.(e)
  } finally {
    uploading.value = false
  }
}

async function onActivate(row: OtaPackageInfo) {
  try {
    await activateOtaPackage(row.id)
    ElMessage.success('已设为目标版本')
    emit('changed')
    await reload()
  } catch (e: any) {
    ElMessage.error(e?.message || '激活失败')
  }
}

async function onDelete(row: OtaPackageInfo) {
  try {
    await ElMessageBox.confirm(`删除版本包 ${row.id}？`, '确认删除', { type: 'warning' })
    await deleteOtaPackage(row.id)
    ElMessage.success('已删除')
    emit('changed')
    await reload()
  } catch {
    /* cancel */
  }
}

onMounted(() => void reload())
</script>

<style scoped>
.ota-packages {
  color: rgb(var(--mg-text-tint-rgb));
}
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 10px;
  align-items: center;
}
.car-select {
  width: 240px;
}
.split {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 12px;
}
.detail {
  border: 1px solid rgba(var(--mg-primary-rgb), 0.14);
  border-radius: 10px;
  padding: 12px;
  min-height: 200px;
  background: rgba(var(--mg-primary-rgb), 0.03);
}
.detail h4 {
  margin: 0 0 10px;
  font-size: 13px;
  color: rgb(var(--mg-text-tint-rgb));
}
.detail ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.detail li {
  display: grid;
  grid-template-columns: 70px 1fr auto;
  gap: 8px;
  font-size: 12px;
}
.key {
  color: var(--mg-primary);
  font-weight: 600;
}
.mono {
  font-family: var(--mg-font-mono);
}
.dim {
  color: rgba(var(--mg-text-hi-rgb), 0.55);
}
.tag {
  margin-left: 6px;
}
@media (max-width: 960px) {
  .split {
    grid-template-columns: 1fr;
  }
}
</style>
