<script setup lang="ts">
import { onMounted, reactive, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import DataTablePage from '@/components/DataTablePage.vue'
import {
  deleteModel,
  deleteTrainedModel,
  getModelExportJobs,
  getModelList,
  getTrainedModelArtifacts,
  getTrainedModelLineage,
  getTrainedModels,
  type ModelArtifact,
  type ModelExportJob,
  type ModelLineageEdge,
} from '@/api/modules/model'
import { MODEL_SOURCE_MAP, MODEL_TYPE_MAP, PURPOSE_MAP } from '@/constants'
import type { ModelItem, TrainedModel } from '@/types'
import { mergeStatusLabel, mergeStatusType, statusLabel, statusTagType } from '@/utils/status'

const router = useRouter()

type TabKey = 'config' | 'trained'
type TrainedModelRuntime = {
  artifacts: ModelArtifact[]
  lineage: { parents: ModelLineageEdge[]; children: ModelLineageEdge[] }
  exportJobs: ModelExportJob[]
  loading: boolean
  loaded: boolean
}

const activeTab = ref<TabKey>('config')
const loading = ref(false)
const configList = ref<ModelItem[]>([])
const trainedList = ref<TrainedModel[]>([])
const runtimeMap = reactive<Record<string, TrainedModelRuntime>>({})

function asModelItem(row: unknown): ModelItem {
  return row as ModelItem
}

function asTrainedModel(row: unknown): TrainedModel {
  return row as TrainedModel
}

function runtimeKey(row: TrainedModel) {
  return String(row.id || row.name)
}

function runtimeOf(row: TrainedModel) {
  const key = runtimeKey(row)
  if (!runtimeMap[key]) {
    runtimeMap[key] = {
      artifacts: [],
      lineage: { parents: [], children: [] },
      exportJobs: [],
      loading: false,
      loaded: false,
    }
  }
  return runtimeMap[key]
}

function formatTime(value?: string) {
  return value ? new Date(value).toLocaleString('zh-CN') : '-'
}

function formatBytes(value?: number) {
  const size = Number(value || 0)
  if (size <= 0) return '-'
  if (size < 1024) return `${size} B`
  if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`
  if (size < 1024 * 1024 * 1024) return `${(size / 1024 / 1024).toFixed(1)} MB`
  return `${(size / 1024 / 1024 / 1024).toFixed(2)} GB`
}

function relationLabel(value?: string) {
  const map: Record<string, string> = {
    fine_tuned_from: '由基座模型微调生成',
    merged_from_adapter: '由 Adapter 合并导出',
  }
  return map[value || ''] || value || '-'
}

function artifactTypeLabel(value?: string) {
  const map: Record<string, string> = {
    adapter: 'Adapter 权重',
    merged_model: '合并模型',
    quantized_model: '量化模型',
  }
  return map[value || ''] || value || '-'
}

async function loadConfig() {
  loading.value = true
  try {
    configList.value = (await getModelList()) || []
  } finally {
    loading.value = false
  }
}

async function loadTrained() {
  loading.value = true
  try {
    const res = await getTrainedModels()
    trainedList.value = res?.models || []
  } finally {
    loading.value = false
  }
}

function loadData() {
  if (activeTab.value === 'config') loadConfig()
  else loadTrained()
}

async function loadTrainedRuntime(row: TrainedModel, force = false) {
  const state = runtimeOf(row)
  if (state.loading || (state.loaded && !force)) return
  state.loading = true
  try {
    const id = row.id || row.name
    const [artifacts, lineage, exportJobs] = await Promise.all([
      getTrainedModelArtifacts(id),
      getTrainedModelLineage(id),
      getModelExportJobs(id),
    ])
    state.artifacts = artifacts || []
    state.lineage = {
      parents: lineage?.parents || [],
      children: lineage?.children || [],
    }
    state.exportJobs = exportJobs || []
    state.loaded = true
  } finally {
    state.loading = false
  }
}

function handleExpandChange(row: TrainedModel, expandedRows: TrainedModel[]) {
  if (expandedRows.some((item) => runtimeKey(item) === runtimeKey(row))) {
    loadTrainedRuntime(row)
  }
}

async function handleDeleteConfig(row: ModelItem) {
  await deleteModel(row.id)
  configList.value = configList.value.filter((item) => item.id !== row.id)
  await loadConfig()
  ElMessage.success('删除成功')
}

async function handleDeleteWeight(row: TrainedModel) {
  await ElMessageBox.confirm(`确定要删除模型“${row.name}”的权重文件吗？合并模型不受影响。`, '确认删除', {
    type: 'warning',
  })
  await deleteTrainedModel(row.id || row.name, 'lora')
  trainedList.value = trainedList.value.filter((item) => item.name !== row.name && item.id !== row.id)
  await loadTrained()
  ElMessage.success('权重已删除')
}

function handleMerge(row: TrainedModel) {
  router.push({
    path: '/model-manage/merge',
    query: {
      model: row.name,
      method: row.train_methods?.[0]?.name || 'lora',
    },
  })
}

function editModel(row: ModelItem) {
  router.push(`/model-manage/${row.id}/edit`)
}

function handleCreateClick() {
  if (activeTab.value === 'config') {
    router.push('/model-manage/create')
  }
}

function handleRefresh() {
  if (activeTab.value === 'config') loadConfig()
  else loadTrained()
}

watch(activeTab, loadData)

onMounted(loadData)
</script>

<template>
  <div class="model-manage-page">
    <DataTablePage
      v-if="activeTab === 'config'"
      title="模型"
      :data="configList"
      :loading="loading"
      searchable
      :search-fields="['name', 'description']"
      create-text="添加模型"
      :delete-fn="handleDeleteConfig"
      row-key="id"
      @create="handleCreateClick"
      @refresh="loadConfig"
    >
      <template #title>
        <div class="capsule-tabs">
          <button class="capsule-tab-item active" @click="activeTab = 'config'">配置模型</button>
          <button class="capsule-tab-item" @click="activeTab = 'trained'">训练模型</button>
        </div>
      </template>
      <template #columns>
        <el-table-column label="模型名称" prop="name" align="center" min-width="180" />
        <el-table-column label="模型类型" align="center" width="140">
          <template #default="{ row }">
            <el-tag type="primary" size="small">{{ MODEL_TYPE_MAP[row.type] || row.type || '-' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="用途" align="center" width="110">
          <template #default="{ row }">
            <el-tag :type="(PURPOSE_MAP[row.purpose]?.type || 'info') as any" size="small">
              {{ PURPOSE_MAP[row.purpose]?.text || row.purpose || '-' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="模型来源" align="center" width="120">
          <template #default="{ row }">{{ MODEL_SOURCE_MAP[row.model_source] || row.model_source || '-' }}</template>
        </el-table-column>
        <el-table-column label="描述" align="center" show-overflow-tooltip>
          <template #default="{ row }">{{ row.description || '-' }}</template>
        </el-table-column>
        <el-table-column label="创建时间" align="center" width="180">
          <template #default="{ row }">{{ formatTime(row.create_time) }}</template>
        </el-table-column>
      </template>
      <template #actions="{ row }">
        <el-button type="primary" link size="small" @click="editModel(asModelItem(row))">
          <i class="fa fa-edit" /> 编辑
        </el-button>
        <el-button type="danger" link size="small" @click="handleDeleteConfig(asModelItem(row))">
          <i class="fa fa-trash-o" /> 删除
        </el-button>
      </template>
    </DataTablePage>

    <DataTablePage
      v-else
      title="训练模型"
      :data="trainedList"
      :loading="loading"
      searchable
      :search-fields="['name']"
      row-key="id"
      @expand-change="handleExpandChange"
      @refresh="handleRefresh"
    >
      <template #title>
        <div class="capsule-tabs">
          <button class="capsule-tab-item" @click="activeTab = 'config'">配置模型</button>
          <button class="capsule-tab-item active" @click="activeTab = 'trained'">训练模型</button>
        </div>
      </template>
      <template #columns>
        <el-table-column type="expand" width="48">
          <template #default="{ row }">
            <div class="runtime-panel" v-loading="runtimeOf(asTrainedModel(row)).loading">
              <section>
                <div class="panel-title">
                  <strong>模型产物</strong>
                  <el-button link type="primary" size="small" @click="loadTrainedRuntime(asTrainedModel(row), true)">刷新</el-button>
                </div>
                <el-table :data="runtimeOf(asTrainedModel(row)).artifacts" size="small" empty-text="暂无产物记录">
                  <el-table-column label="类型" width="120">
                    <template #default="{ row: item }">{{ artifactTypeLabel(item.artifact_type) }}</template>
                  </el-table-column>
                  <el-table-column label="路径" prop="path" min-width="280" show-overflow-tooltip />
                  <el-table-column label="大小" width="110">
                    <template #default="{ row: item }">{{ formatBytes(item.size_bytes) }}</template>
                  </el-table-column>
                  <el-table-column label="Checksum" min-width="220" show-overflow-tooltip>
                    <template #default="{ row: item }">{{ item.checksum_sha256 || '-' }}</template>
                  </el-table-column>
                </el-table>
              </section>

              <section>
                <div class="panel-title"><strong>模型血缘</strong></div>
                <el-table
                  :data="[...runtimeOf(asTrainedModel(row)).lineage.parents, ...runtimeOf(asTrainedModel(row)).lineage.children]"
                  size="small"
                  empty-text="暂无血缘记录"
                >
                  <el-table-column label="关系" width="180">
                    <template #default="{ row: item }">{{ relationLabel(item.relation_type) }}</template>
                  </el-table-column>
                  <el-table-column label="父资源" min-width="220">
                    <template #default="{ row: item }">
                      {{ item.parent_resource_type }} / {{ item.parent_resource_id }}
                    </template>
                  </el-table-column>
                  <el-table-column label="子资源" min-width="220">
                    <template #default="{ row: item }">
                      {{ item.child_resource_type }} / {{ item.child_resource_id }}
                    </template>
                  </el-table-column>
                  <el-table-column label="Compute Job" prop="compute_job_id" min-width="160" show-overflow-tooltip />
                </el-table>
              </section>

              <section>
                <div class="panel-title"><strong>导出任务</strong></div>
                <el-table :data="runtimeOf(asTrainedModel(row)).exportJobs" size="small" empty-text="暂无导出任务">
                  <el-table-column label="任务ID" prop="id" min-width="160" show-overflow-tooltip />
                  <el-table-column label="类型" prop="export_type" width="100" />
                  <el-table-column label="状态" width="100">
                    <template #default="{ row: item }">
                      <el-tag :type="statusTagType(item.status)" size="small">{{ statusLabel(item.status) }}</el-tag>
                    </template>
                  </el-table-column>
                  <el-table-column label="输出目录" prop="output_dir" min-width="260" show-overflow-tooltip />
                  <el-table-column label="创建时间" width="180">
                    <template #default="{ row: item }">{{ formatTime(item.create_time) }}</template>
                  </el-table-column>
                </el-table>
              </section>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="模型名称" prop="name" align="center" min-width="180" />
        <el-table-column label="训练方法" align="center" width="110">
          <template #default="{ row }">{{ row.train_methods?.[0]?.name || '-' }}</template>
        </el-table-column>
        <el-table-column label="基座模型" align="center" show-overflow-tooltip>
          <template #default="{ row }">{{ row.base_model_path || '-' }}</template>
        </el-table-column>
        <el-table-column label="合并状态" align="center" width="110">
          <template #default="{ row }">
            <el-tag :type="mergeStatusType(asTrainedModel(row))" size="small">{{ mergeStatusLabel(asTrainedModel(row)) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="创建时间" align="center" width="180">
          <template #default="{ row }">{{ formatTime(row.create_time) }}</template>
        </el-table-column>
      </template>
      <template #actions="{ row }">
        <div class="action-buttons">
          <el-button v-if="!row.merged && !row.merging" type="primary" link size="small" @click="handleMerge(asTrainedModel(row))">
            <i class="fa fa-code-fork" /> 合并权重
          </el-button>
          <el-button v-else-if="row.merging" type="info" link size="small" :loading="true" disabled>合并中</el-button>
          <el-button type="warning" link size="small" @click="handleDeleteWeight(asTrainedModel(row))">
            <i class="fa fa-eraser" /> 删除权重
          </el-button>
        </div>
      </template>
    </DataTablePage>
  </div>
</template>

<style scoped lang="scss">
.model-manage-page {
  height: 100%;
}

.capsule-tabs {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  background: #f1f5f9;
}

.capsule-tab-item {
  border: 0;
  border-radius: 6px;
  background: transparent;
  padding: 6px 20px;
  color: #64748b;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;

  &.active {
    background: #fff;
    color: #4f46e5;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    font-weight: 600;
  }
}

.action-buttons {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.runtime-panel {
  display: grid;
  gap: 16px;
  padding: 16px 24px;
  background: #f8fafc;
}

.panel-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  color: #1f2937;
}
</style>
