<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
  disableComputeNode,
  drainComputeNode,
  enableComputeNode,
  getComputeGpus,
  getComputeNodes,
  getComputeQueue,
  getNodeReplicas,
  testComputeNode,
  type ComputeGpu,
  type ComputeNode,
  type ComputeQueueItem,
  type ResourceReplica,
} from '@/api/modules/compute'

const route = useRoute()
const router = useRouter()

const activeTab = ref(String(route.query.tab || 'nodes'))
const loading = ref(false)
const nodes = ref<ComputeNode[]>([])
const gpus = ref<ComputeGpu[]>([])
const queue = ref<ComputeQueueItem[]>([])
const replicas = ref<ResourceReplica[]>([])
const selectedNodeId = ref('')
const lastUpdated = ref('')
let timer: ReturnType<typeof setInterval> | null = null

const selectedNode = computed(() => nodes.value.find((item) => item.id === selectedNodeId.value))
const enabledNodes = computed(() => nodes.value.filter((item) => item.enabled).length)
const busyGpus = computed(() => gpus.value.filter((item) => item.status === 'busy' || item.status === 'reserved').length)
const totalRunningJobs = computed(() => nodes.value.reduce((sum, item) => sum + item.current_running_jobs, 0))

watch(
  () => route.query.tab,
  (tab) => {
    activeTab.value = String(tab || 'nodes')
  },
)

async function load() {
  loading.value = true
  try {
    const [nodeList, gpuList, queueList] = await Promise.all([
      getComputeNodes(),
      getComputeGpus(),
      getComputeQueue(),
    ])
    nodes.value = nodeList
    gpus.value = gpuList
    queue.value = queueList
    if (!selectedNodeId.value && nodeList.length) selectedNodeId.value = nodeList[0].id
    await loadReplicas()
    lastUpdated.value = new Date().toLocaleTimeString('zh-CN', { hour12: false })
  } finally {
    loading.value = false
  }
}

async function loadReplicas() {
  if (!selectedNodeId.value) {
    replicas.value = []
    return
  }
  replicas.value = await getNodeReplicas(selectedNodeId.value)
}

async function changeTab(name: string | number) {
  await router.replace({ path: '/compute', query: { tab: String(name) } })
}

async function handleNodeAction(action: 'enable' | 'disable' | 'drain' | 'test', node: any) {
  const nodeId = String(node.id)
  if (action === 'enable') await enableComputeNode(nodeId)
  if (action === 'disable') await disableComputeNode(nodeId)
  if (action === 'drain') await drainComputeNode(nodeId)
  if (action === 'test') await testComputeNode(nodeId)
  await load()
}

function nodeStatusType(status: string) {
  if (status === 'online') return 'success'
  if (status === 'draining' || status === 'maintenance') return 'warning'
  return 'info'
}

function taskStatusType(status: string) {
  if (status === 'running') return 'success'
  if (status === 'syncing' || status === 'queued') return 'warning'
  if (status === 'failed') return 'danger'
  return 'info'
}

function gpuStatusType(status: string) {
  if (status === 'busy') return 'success'
  if (status === 'reserved') return 'warning'
  return 'info'
}

onMounted(() => {
  load()
  timer = setInterval(load, 5000)
})

onUnmounted(() => {
  if (timer) clearInterval(timer)
})
</script>

<template>
  <section class="compute-page" v-loading="loading">
    <header class="compute-header">
      <div>
        <h1>算力节点</h1>
        <p>维护训练算力节点、GPU 状态、任务队列和模型/数据集本地副本。</p>
      </div>
      <div class="header-actions">
        <span v-if="lastUpdated" class="last-updated">更新 {{ lastUpdated }}</span>
        <el-button @click="load">刷新</el-button>
      </div>
    </header>

    <div class="summary-grid">
      <div class="summary-tile">
        <span>在线节点</span>
        <strong>{{ enabledNodes }} / {{ nodes.length }}</strong>
      </div>
      <div class="summary-tile">
        <span>GPU 占用</span>
        <strong>{{ busyGpus }} / {{ gpus.length }}</strong>
      </div>
      <div class="summary-tile">
        <span>运行任务</span>
        <strong>{{ totalRunningJobs }}</strong>
      </div>
      <div class="summary-tile">
        <span>队列任务</span>
        <strong>{{ queue.length }}</strong>
      </div>
    </div>

    <el-tabs v-model="activeTab" class="compute-tabs" @tab-change="changeTab">
      <el-tab-pane label="节点" name="nodes">
        <el-table :data="nodes" height="100%">
          <el-table-column prop="code" label="节点编码" min-width="150" />
          <el-table-column prop="name" label="节点名称" min-width="150" />
          <el-table-column label="状态" width="120">
            <template #default="{ row }">
              <el-tag :type="nodeStatusType(row.scheduler_status)">{{ row.scheduler_status }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="启用" width="90">
            <template #default="{ row }">
              <el-tag :type="row.enabled ? 'success' : 'info'">{{ row.enabled ? '启用' : '停用' }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="scheduler_weight" label="权重" width="90" />
          <el-table-column label="标签" min-width="220">
            <template #default="{ row }">
              <el-space wrap>
                <el-tag v-for="tag in row.tags" :key="tag" effect="plain">{{ tag }}</el-tag>
              </el-space>
            </template>
          </el-table-column>
          <el-table-column label="任务/GPU" width="120">
            <template #default="{ row }">{{ row.current_running_jobs }} / {{ row.gpu_count }}</template>
          </el-table-column>
          <el-table-column label="服务地址" min-width="260">
            <template #default="{ row }">
              <div class="mono">{{ row.api_base_url }}</div>
              <div class="muted mono">{{ row.file_gateway_url }}</div>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="260" fixed="right">
            <template #default="{ row }">
              <el-button size="small" @click="handleNodeAction('test', row)">测试</el-button>
              <el-button v-if="row.enabled" size="small" @click="handleNodeAction('disable', row)">停用</el-button>
              <el-button v-else size="small" type="primary" @click="handleNodeAction('enable', row)">启用</el-button>
              <el-button size="small" type="warning" plain @click="handleNodeAction('drain', row)">维护</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-tab-pane>

      <el-tab-pane label="GPU" name="gpus">
        <el-table :data="gpus" height="100%">
          <el-table-column label="GPU" min-width="220">
            <template #default="{ row }">
              <strong>{{ row.node_code }} / GPU {{ row.id }}</strong>
              <div class="muted">{{ row.name }}</div>
            </template>
          </el-table-column>
          <el-table-column label="状态" width="100">
            <template #default="{ row }">
              <el-tag :type="gpuStatusType(row.status)">{{ row.status }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="利用率" min-width="180">
            <template #default="{ row }">
              <el-progress :percentage="row.gpu_percent" :stroke-width="8" />
            </template>
          </el-table-column>
          <el-table-column label="显存" min-width="190">
            <template #default="{ row }">
              <el-progress :percentage="Math.round(row.memory_percent)" :stroke-width="8" />
              <span class="muted">{{ row.memory_used_gb }} / {{ row.memory_total_gb }} GB</span>
            </template>
          </el-table-column>
          <el-table-column label="温度/功耗" width="150">
            <template #default="{ row }">{{ row.temperature }} C / {{ row.power_w }} W</template>
          </el-table-column>
          <el-table-column label="进程" min-width="220">
            <template #default="{ row }">
              <span v-if="!row.processes?.length" class="muted">空闲</span>
              <div v-for="process in row.processes" :key="process.pid">
                {{ process.task_name }} <span class="muted">PID {{ process.pid }}</span>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </el-tab-pane>

      <el-tab-pane label="队列" name="queue">
        <el-table :data="queue" height="100%">
          <el-table-column prop="name" label="任务名称" min-width="200" />
          <el-table-column label="状态" width="110">
            <template #default="{ row }">
              <el-tag :type="taskStatusType(row.status)">{{ row.status }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="进度" min-width="220">
            <template #default="{ row }">
              <el-progress :percentage="row.progress" :stroke-width="8" />
            </template>
          </el-table-column>
          <el-table-column prop="compute_node_id" label="节点" width="140" />
          <el-table-column label="GPU" width="120">
            <template #default="{ row }">{{ row.gpus?.join(', ') || '-' }}</template>
          </el-table-column>
          <el-table-column prop="create_time" label="创建时间" width="190" />
        </el-table>
      </el-tab-pane>

      <el-tab-pane label="资源副本" name="replicas">
        <div class="replica-toolbar">
          <el-select v-model="selectedNodeId" filterable @change="loadReplicas">
            <el-option v-for="node in nodes" :key="node.id" :label="`${node.code} - ${node.name}`" :value="node.id" />
          </el-select>
          <span v-if="selectedNode" class="muted">当前节点 {{ selectedNode.api_base_url }}</span>
        </div>
        <el-table :data="replicas" height="100%">
          <el-table-column prop="resource_type" label="资源类型" width="110" />
          <el-table-column prop="resource_id" label="资源 ID" min-width="180" />
          <el-table-column prop="local_path" label="本地路径" min-width="300" />
          <el-table-column prop="status" label="状态" width="110" />
          <el-table-column prop="sync_status" label="同步状态" width="120" />
          <el-table-column prop="create_time" label="创建时间" width="190" />
        </el-table>
      </el-tab-pane>
    </el-tabs>
  </section>
</template>

<style scoped lang="scss">
.compute-page {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-height: 0;
  height: 100%;
  padding: 24px;
  background: #fff;
}

.compute-header {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;

  h1 {
    margin: 0;
    font-size: 24px;
    font-weight: 650;
    color: #111827;
  }

  p {
    margin: 8px 0 0;
    color: #64748b;
  }
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.last-updated,
.muted {
  color: #64748b;
  font-size: 12px;
}

.summary-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}

.summary-tile {
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 14px 16px;
  background: #f8fafc;

  span {
    display: block;
    color: #64748b;
    font-size: 12px;
  }

  strong {
    display: block;
    margin-top: 8px;
    color: #111827;
    font-size: 24px;
  }
}

.compute-tabs {
  flex: 1;
  min-height: 0;

  :deep(.el-tabs__content) {
    height: calc(100% - 56px);
  }

  :deep(.el-tab-pane) {
    height: 100%;
  }
}

.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
}

.replica-toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 12px;

  .el-select {
    width: 280px;
  }
}

@media (max-width: 960px) {
  .compute-header,
  .header-actions,
  .replica-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .summary-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
</style>
