<template>
  <div class="migration-record-page">
    <div class="page-header">
      <div>
        <h2>虚拟机迁移记录</h2>
        <p>查看宿主机迁移、跨服务数据迁移及完整迁移链路</p>
      </div>
      <el-button :icon="Refresh" @click="loadList">刷新</el-button>
    </div>

    <el-card shadow="never" class="filter-card">
      <el-form :inline="true" :model="filters">
        <el-form-item label="迁移类型">
          <el-select v-model="filters.migration_type" clearable placeholder="全部" style="width:150px">
            <el-option label="宿主机迁移" value="host_migrate" />
            <el-option label="跨服务数据迁移" value="data_migrate" />
          </el-select>
        </el-form-item>
        <el-form-item label="状态">
          <el-select v-model="filters.status" clearable placeholder="全部" style="width:140px">
            <el-option v-for="s in statusOptions" :key="s.value" :label="s.label" :value="s.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="链路 ID"><el-input v-model.trim="filters.chain_id" clearable placeholder="chain_id" style="width:210px" /></el-form-item>
        <el-form-item label="任务 ID"><el-input v-model.trim="filters.task_id" clearable placeholder="task_id" style="width:210px" /></el-form-item>
        <el-form-item label="用户 ID"><el-input-number v-model="filters.user_id" :min="1" :controls="false" style="width:120px" /></el-form-item>
        <el-form-item label="用户商品 ID"><el-input-number v-model="filters.user_goods_id" :min="1" :controls="false" style="width:130px" /></el-form-item>
        <el-form-item label="开始时间">
          <el-date-picker v-model="filters.started_range" type="datetimerange" start-placeholder="开始" end-placeholder="结束" value-format="YYYY-MM-DD HH:mm:ss" style="width:350px" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" :icon="Search" @click="search">查询</el-button>
          <el-button @click="resetFilters">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card shadow="never">
      <el-table :data="records" v-loading="loading" stripe>
        <el-table-column prop="id" label="记录 ID" width="90" />
        <el-table-column label="类型" width="130"><template #default="{ row }"><el-tag :type="row.migration_type === 'data_migrate' ? 'primary' : 'info'">{{ typeLabel(row.migration_type) }}</el-tag></template></el-table-column>
        <el-table-column label="状态" width="105"><template #default="{ row }"><el-tag :type="statusType(row.status)">{{ statusLabel(row.status) }}</el-tag></template></el-table-column>
        <el-table-column label="源端" min-width="180">
          <template #default="{ row }"><div class="endpoint"><span>服务 #{{ row.source_service_id || '-' }}</span><el-link v-if="row.source_host_id" type="primary" @click="goHost(row.source_service_id, row.source_host_id)">宿主机 #{{ row.source_host_id }}</el-link><el-link v-if="row.source_vm_id" type="primary" @click="goVm(row.source_service_id, row.source_vm_id)">VM #{{ row.source_vm_id }}</el-link></div></template>
        </el-table-column>
        <el-table-column label="目标端" min-width="180">
          <template #default="{ row }"><div class="endpoint"><span>服务 #{{ row.target_service_id || '-' }}</span><el-link v-if="row.target_host_id" type="primary" @click="goHost(row.target_service_id, row.target_host_id)">宿主机 #{{ row.target_host_id }}</el-link><el-link v-if="row.target_vm_id" type="primary" @click="goVm(row.target_service_id, row.target_vm_id)">VM #{{ row.target_vm_id }}</el-link></div></template>
        </el-table-column>
        <el-table-column label="关联对象" min-width="145">
          <template #default="{ row }"><div class="endpoint"><el-link v-if="row.user_id" type="primary" @click="goUser(row.user_id)">用户 #{{ row.user_id }}</el-link><el-link v-if="row.user_goods_id" type="primary" @click="goUserGoods(row.user_goods_id)">用户商品 #{{ row.user_goods_id }}</el-link><span v-if="row.operator_admin_id">管理员 #{{ row.operator_admin_id }}</span></div></template>
        </el-table-column>
        <el-table-column label="链路" min-width="155"><template #default="{ row }"><el-link type="primary" class="mono" @click="openChain(row)">{{ shortId(row.chain_id) }}</el-link><div class="muted">序号 {{ row.chain_seq || 1 }}</div></template></el-table-column>
        <el-table-column label="耗时" width="110"><template #default="{ row }">{{ durationText(row) }}</template></el-table-column>
        <el-table-column label="开始时间" width="170"><template #default="{ row }">{{ formatTime(row.started_at || row.CreatedAt) }}</template></el-table-column>
        <el-table-column label="操作" width="125" fixed="right"><template #default="{ row }"><el-button link type="primary" @click="openDetail(row)">详情</el-button><el-button link type="primary" @click="openChain(row)">迁移链</el-button></template></el-table-column>
      </el-table>
      <div class="pagination"><el-pagination v-model:current-page="page" v-model:page-size="count" :page-sizes="[10,20,50,100]" :total="total" layout="total, sizes, prev, pager, next" @current-change="loadList" @size-change="sizeChange" /></div>
    </el-card>

    <el-drawer v-model="detailVisible" title="迁移记录详情" size="760px" destroy-on-close>
      <div v-loading="detailLoading" v-if="currentRecord">
        <el-descriptions :column="2" border>
          <el-descriptions-item label="记录 ID">{{ currentRecord.id }}</el-descriptions-item><el-descriptions-item label="状态"><el-tag :type="statusType(currentRecord.status)">{{ statusLabel(currentRecord.status) }}</el-tag></el-descriptions-item>
          <el-descriptions-item label="迁移类型">{{ typeLabel(currentRecord.migration_type) }}</el-descriptions-item><el-descriptions-item label="迁移链序号">{{ currentRecord.chain_seq || 1 }}</el-descriptions-item>
          <el-descriptions-item label="链路 ID" :span="2"><span class="mono">{{ currentRecord.chain_id || '-' }}</span></el-descriptions-item>
          <el-descriptions-item label="任务 ID" :span="2"><span class="mono">{{ currentRecord.task_id || '-' }}</span></el-descriptions-item>
          <el-descriptions-item label="导出任务"><span class="mono">{{ currentRecord.export_task_id || '-' }}</span></el-descriptions-item><el-descriptions-item label="导入任务"><span class="mono">{{ currentRecord.import_task_id || '-' }}</span></el-descriptions-item>
          <el-descriptions-item label="开始时间">{{ formatTime(currentRecord.started_at) }}</el-descriptions-item><el-descriptions-item label="完成时间">{{ formatTime(currentRecord.completed_at) }}</el-descriptions-item>
          <el-descriptions-item v-if="currentRecord.error_message" label="错误信息" :span="2"><span class="error-text">{{ currentRecord.error_message }}</span></el-descriptions-item>
        </el-descriptions>
        <el-tabs class="snapshot-tabs">
          <el-tab-pane v-for="item in snapshotFields" :key="item.key" :label="item.label"><pre class="json-view">{{ prettySnapshot(currentRecord[item.key]) }}</pre></el-tab-pane>
        </el-tabs>
      </div>
    </el-drawer>

    <el-dialog v-model="chainVisible" title="迁移链路" width="820px" destroy-on-close>
      <div v-loading="chainLoading">
        <div class="chain-id">链路 ID：<span class="mono">{{ chainData.chain_id || '-' }}</span></div>
        <el-timeline v-if="chainData.records?.length">
          <el-timeline-item v-for="item in chainData.records" :key="item.id" :type="statusType(item.status)" :timestamp="formatTime(item.started_at || item.CreatedAt)" placement="top">
            <el-card shadow="never"><div class="chain-card-title"><span>#{{ item.id }} · 第 {{ item.chain_seq || 1 }} 步 · {{ typeLabel(item.migration_type) }}</span><el-tag :type="statusType(item.status)" size="small">{{ statusLabel(item.status) }}</el-tag></div><div class="chain-route">服务 {{ item.source_service_id || '-' }} / VM {{ item.source_vm_id || '-' }} → 服务 {{ item.target_service_id || '-' }} / VM {{ item.target_vm_id || '-' }}</div><el-button link type="primary" @click="chainVisible=false; openDetail(item)">查看详情</el-button></el-card>
          </el-timeline-item>
        </el-timeline><el-empty v-else description="暂无迁移链记录" />
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
import { onMounted, reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { Refresh, Search } from '@element-plus/icons-vue'
import { getVmMigrationRecordList, getVmMigrationRecordDetail, getVmMigrationRecordChain } from '@/api/admin/kvmService'
import { extractApiError } from '@/utils/kvmErrorUtil'

const router = useRouter()
const route = useRoute()
const loading = ref(false), records = ref([]), total = ref(0), page = ref(1), count = ref(20)
const filters = reactive({ migration_type: '', status: '', chain_id: '', task_id: '', user_id: null, user_goods_id: null, started_range: [] })
const statusOptions = ['pending','exporting','importing','running','success','failed','aborted','warning'].map(value => ({ value, label: ({ pending:'等待中',exporting:'导出中',importing:'导入中',running:'执行中',success:'成功',failed:'失败',aborted:'已中断',warning:'警告' })[value] }))
const statusLabel = s => statusOptions.find(x => x.value === s)?.label || s || '-'
const statusType = s => ({ success:'success', failed:'danger', aborted:'info', warning:'warning', exporting:'warning', importing:'primary', running:'primary', pending:'info' })[s] || 'info'
const typeLabel = t => ({ host_migrate:'宿主机迁移', data_migrate:'跨服务数据迁移' })[t] || t || '-'
const formatTime = value => { if (!value) return '-'; const d = new Date(value); return Number.isNaN(d.getTime()) ? String(value) : d.toLocaleString('zh-CN', { hour12:false }) }
const shortId = value => !value ? '-' : (value.length > 18 ? `${value.slice(0,8)}…${value.slice(-6)}` : value)
const durationText = row => { if (!row.started_at) return '-'; const end = row.completed_at ? new Date(row.completed_at) : new Date(); const sec = Math.max(0, Math.floor((end-new Date(row.started_at))/1000)); return sec >= 3600 ? `${Math.floor(sec/3600)}时${Math.floor(sec%3600/60)}分` : sec >= 60 ? `${Math.floor(sec/60)}分${sec%60}秒` : `${sec}秒` }
const buildParams = () => { const p = { page:page.value, count:count.value }; ['migration_type','status','chain_id','task_id','user_id','user_goods_id'].forEach(k => { if (filters[k] !== '' && filters[k] != null) p[k]=filters[k] }); if (filters.started_range?.length===2) [p.started_at_start,p.started_at_end]=filters.started_range; return p }
const loadList = async () => { loading.value=true; try { const res=await getVmMigrationRecordList(buildParams()); if(res?.data?.code!==200) throw new Error(extractApiError(res?.data,'加载迁移记录失败')); const d=res.data.data||{}; records.value=d.data||[]; total.value=d.all_count||0 } catch(e){ ElMessage.error(e.message||extractApiError(e?.response?.data,'加载迁移记录失败')) } finally { loading.value=false } }
const search = () => { page.value=1; loadList() }, sizeChange = () => { page.value=1; loadList() }
const resetFilters = () => { Object.assign(filters,{ migration_type:'',status:'',chain_id:'',task_id:'',user_id:null,user_goods_id:null,started_range:[] }); search() }
const detailVisible=ref(false), detailLoading=ref(false), currentRecord=ref(null)
const snapshotFields=[{key:'request_snapshot',label:'请求参数'},{key:'before_snapshot',label:'迁移前快照'},{key:'after_snapshot',label:'迁移后快照'},{key:'manifest_snapshot',label:'迁移清单'},{key:'warning_snapshot',label:'警告'}]
const prettySnapshot = value => { if(!value) return '暂无数据'; try { return JSON.stringify(typeof value==='string'?JSON.parse(value):value,null,2) } catch { return String(value) } }
const openDetail = async row => { detailVisible.value=true; currentRecord.value=row; detailLoading.value=true; try { const res=await getVmMigrationRecordDetail({id:row.id}); if(res?.data?.code!==200) throw new Error(extractApiError(res?.data,'加载详情失败')); currentRecord.value=res.data.data?.record||res.data.data||row } catch(e){ ElMessage.error(e.message||extractApiError(e?.response?.data,'加载详情失败')) } finally { detailLoading.value=false } }
const chainVisible=ref(false), chainLoading=ref(false), chainData=reactive({chain_id:'',records:[]})
const openChain = async row => { chainVisible.value=true; chainLoading.value=true; Object.assign(chainData,{chain_id:row.chain_id||'',records:[]}); try { const params=row.chain_id?{chain_id:row.chain_id}:{id:row.id}; const res=await getVmMigrationRecordChain(params); if(res?.data?.code!==200) throw new Error(extractApiError(res?.data,'加载迁移链失败')); Object.assign(chainData,res.data.data||{}) } catch(e){ ElMessage.error(e.message||extractApiError(e?.response?.data,'加载迁移链失败')) } finally { chainLoading.value=false } }
const goVm=(serviceId,vmId)=>router.push({path:'/virtualization/vm-detail',query:{service_id:serviceId,vm_id:vmId}})
const goHost=(serviceId,hostId)=>router.push({path:'/virtualization/host-detail',query:{service_id:serviceId,host_id:hostId}})
const goUser=userId=>router.push({path:'/user/detail',query:{user_id:userId}})
const goUserGoods=id=>router.push(`/user-goods/detail/${id}`)
onMounted(async () => {
  if (route.query.chain_id) filters.chain_id = String(route.query.chain_id)
  if (route.query.user_goods_id) filters.user_goods_id = Number(route.query.user_goods_id)
  await loadList()
  if (route.query.id) openDetail({ id: Number(route.query.id) })
})
</script>

<style scoped>
.migration-record-page{padding:20px}.page-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.page-header h2{font-size:20px;margin:0 0 6px}.page-header p{margin:0;color:#86909c;font-size:13px}.filter-card{margin-bottom:16px}.filter-card :deep(.el-form-item){margin-bottom:8px}.endpoint{display:flex;flex-direction:column;align-items:flex-start;gap:3px}.mono{font-family:Consolas,monospace;font-size:12px}.muted{font-size:12px;color:#86909c;margin-top:3px}.pagination{display:flex;justify-content:flex-end;margin-top:16px}.snapshot-tabs{margin-top:18px}.json-view{margin:0;padding:14px;max-height:460px;overflow:auto;background:#f7f8fa;border:1px solid #ebeef5;border-radius:6px;white-space:pre-wrap;word-break:break-all;font:12px/1.6 Consolas,monospace}.error-text{color:#f56c6c}.chain-id{margin-bottom:20px;color:#606266}.chain-card-title{display:flex;justify-content:space-between;align-items:center;font-weight:600}.chain-route{margin:10px 0;color:#606266;font-size:13px}
</style>
