<template>
  <div class="host-manage-container">
    <div class="page-header" v-if="!embedded">
      <div class="header-left">
        <el-button @click="goBack" :icon="ArrowLeft">返回</el-button>
        <div class="header-info">
          <h3>宿主机管理</h3>
          <span class="sub-info" v-if="serviceName">所属主控服务：{{ serviceName }}</span>
        </div>
      </div>
      <div class="header-right">
        <el-button type="warning" @click="openTokenDialog">
          <el-icon><Key /></el-icon>创建注册令牌
        </el-button>
        <el-button type="primary" @click="handleAdd">
          <el-icon><Plus /></el-icon>新增宿主机
        </el-button>
        <el-button @click="loadList">
          <el-icon><Refresh /></el-icon>刷新
        </el-button>
      </div>
    </div>
    <div class="embedded-toolbar" v-if="embedded">
      <el-button type="warning" @click="openTokenDialog"><el-icon><Key /></el-icon>创建注册令牌</el-button>
      <el-button type="primary" @click="handleAdd"><el-icon><Plus /></el-icon>新增宿主机</el-button>
      <el-button @click="loadList"><el-icon><Refresh /></el-icon>刷新</el-button>
    </div>

    <!-- 筛选栏 -->
    <div class="filter-bar">
      <el-input v-model="keyword" placeholder="搜索宿主机名称/IP" clearable style="width: 240px" @keyup.enter="handleSearch" @clear="handleSearch">
        <template #prefix><el-icon><Search /></el-icon></template>
      </el-input>
      <el-select v-model="filterGroupId" placeholder="筛选宿主机组" clearable style="width: 180px" @change="handleSearch">
        <el-option v-for="g in hostGroupOptions" :key="g.id" :label="g.name || g.Name" :value="g.id" />
      </el-select>
    </div>

    <!-- 宿主机列表 -->
    <el-table :data="hostList" v-loading="loading" stripe style="width: 100%">
      <el-table-column prop="id" label="ID" width="70" />
      <el-table-column prop="name" label="名称" min-width="140" show-overflow-tooltip />
      <el-table-column label="IP / 服务地址" min-width="200">
        <template #default="{ row }">
          <div class="host-addr">{{ row.ip || '-' }}</div>
          <div class="host-url" v-if="row.base_url">{{ row.base_url }}</div>
        </template>
      </el-table-column>
      <el-table-column label="SSH" width="120">
        <template #default="{ row }">
          <span v-if="row.port">:{{ row.port }}</span>
          <span v-else class="text-muted">-</span>
        </template>
      </el-table-column>
      <el-table-column label="资源限制" min-width="200">
        <template #default="{ row }">
          <div class="resource-info">
            <el-tag size="small" type="info" v-if="row.max_cpu">CPU: {{ row.max_cpu }}核</el-tag>
            <el-tag size="small" type="info" v-if="row.max_memory">内存: {{ formatMemKB(row.max_memory) }}</el-tag>
            <el-tag size="small" type="info" v-if="row.max_disk">磁盘: {{ formatDiskGB(row.max_disk) }}</el-tag>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="带宽" width="180">
        <template #default="{ row }">
          <span v-if="row.rx_bandwidth || row.tx_bandwidth">
            ↓{{ row.rx_bandwidth || 0 }} Mbps / ↑{{ row.tx_bandwidth || 0 }} Mbps
          </span>
          <span v-else class="text-muted">-</span>
        </template>
      </el-table-column>
      <el-table-column label="宿主机组" width="120">
        <template #default="{ row }">
          <span v-if="row.host_group_id">{{ getGroupName(row.host_group_id) }}</span>
          <span v-else class="text-muted">-</span>
        </template>
      </el-table-column>
      <el-table-column label="状态" width="80">
        <template #default="{ row }">
          <el-tag :type="row.is_active ? 'success' : 'danger'" size="small">{{ row.is_active ? '启用' : '禁用' }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="创建时间" width="170">
        <template #default="{ row }">{{ formatTimestamp(row.created_at) }}</template>
      </el-table-column>
      <el-table-column label="操作" width="120" fixed="right">
        <template #default="{ row }">
          <el-button link type="primary" @click="handleGoDetail(row)">编辑</el-button>
          <el-button link type="danger" @click="handleDelete(row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 分页 -->
    <div class="pagination-wrapper" v-if="total > 0">
      <el-pagination v-model:current-page="queryParams.page" v-model:page-size="queryParams.page_size"
        :page-sizes="[10, 20, 50]" :total="total" layout="total, sizes, prev, pager, next"
        @size-change="handleSizeChange" @current-change="handlePageChange" />
    </div>

    <!-- 新建/编辑弹窗 -->
    <el-dialog v-model="dialogVisible" :title="dialogType === 'add' ? '新增宿主机' : '编辑宿主机'" width="800px" destroy-on-close class="tk-dialog">
      <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
        <div class="tk-section">
          <div class="tk-section-title">基本信息</div>
          <el-form-item label="名称" prop="name">
            <el-input v-model="formData.name" placeholder="宿主机名称" />
          </el-form-item>
          <el-form-item label="服务地址" prop="base_url">
            <el-input v-model="formData.base_url" placeholder="宿主机服务 URL" />
          </el-form-item>
          <el-form-item label="IP 地址" prop="ip">
            <el-input v-model="formData.ip" placeholder="宿主机 IP" />
          </el-form-item>
          <el-form-item label="认证Token">
            <el-input v-model="formData.token" placeholder="宿主机服务 Token（可选）" show-password />
          </el-form-item>
        </div>
        <div class="tk-section">
          <div class="tk-section-title">SSH 配置</div>
          <el-form-item label="端口">
            <div class="tk-inline-unit">
              <el-input-number v-model="formData.port" :min="0" :max="65535" placeholder="22" controls-position="right" />
            </div>
          </el-form-item>
          <el-form-item label="用户名">
            <el-input v-model="formData.user" placeholder="默认 tunneluser" />
          </el-form-item>
          <el-form-item label="密码">
            <el-input v-model="formData.password" placeholder="SSH 密码（可选）" show-password />
          </el-form-item>
          <el-form-item label="私钥">
            <el-input v-model="formData.private_key" type="textarea" :rows="4" placeholder="SSH 私钥内容（可选）" />
          </el-form-item>
        </div>
        <div class="tk-section">
          <div class="tk-section-title">资源限制</div>
          <div class="tk-resource-grid">
            <el-form-item label="CPU">
              <el-input-number v-model="formData.max_cpu" :min="0" controls-position="right" /><span class="tk-res-unit">核</span>
            </el-form-item>
            <el-form-item label="内存">
              <el-input-number v-model="memoryDisplay" :min="0" controls-position="right" />
              <el-select v-model="memoryUnit" class="tk-unit-select">
                <el-option v-for="u in memoryUnitOptions" :key="u.label" :label="u.label" :value="u.label" />
              </el-select>
            </el-form-item>
            <el-form-item label="磁盘">
              <el-input-number v-model="diskDisplay" :min="0" controls-position="right" />
              <el-select v-model="diskUnit" class="tk-unit-select">
                <el-option v-for="u in diskUnitOptions" :key="u.label" :label="u.label" :value="u.label" />
              </el-select>
            </el-form-item>
            <el-form-item label="下行带宽">
              <el-input-number v-model="formData.rx_bandwidth" :min="0" controls-position="right" /><span class="tk-res-unit">Mbps</span>
            </el-form-item>
            <el-form-item label="上行带宽">
              <el-input-number v-model="formData.tx_bandwidth" :min="0" controls-position="right" /><span class="tk-res-unit">Mbps</span>
            </el-form-item>
          </div>
        </div>
        <div class="tk-section">
          <div class="tk-section-title clickable" @click="showDiskIoSection = !showDiskIoSection">
            硬盘 IO 限制
            <el-icon class="section-arrow" :class="{ expanded: showDiskIoSection }"><ArrowRight /></el-icon>
            <span class="section-hint">可选，不展开则使用默认值</span>
          </div>
          <div v-show="showDiskIoSection">
            <div class="io-sub-title">
              带宽限制
              <el-select v-model="ioBwUnit" class="tk-unit-select" style="width: 90px; margin-left: 8px">
                <el-option v-for="u in ioBwUnitOptions" :key="u.label" :label="u.label" :value="u.label" />
              </el-select>
            </div>
            <div class="tk-resource-grid">
              <el-form-item v-for="f in diskIoBwFields" :key="f.key" :label="f.label">
                <el-input-number :model-value="+(formData[f.key] / getIoBwFactor()).toFixed(2)" @update:model-value="v => formData[f.key] = Math.round((v || 0) * getIoBwFactor())" :min="0" controls-position="right" />
              </el-form-item>
            </div>
            <div class="io-sub-title">IOPS 限制</div>
            <div class="tk-resource-grid">
              <el-form-item v-for="f in diskIoIopsFields" :key="f.key" :label="f.label">
                <el-input-number v-model="formData[f.key]" :min="0" controls-position="right" />
              </el-form-item>
            </div>
          </div>
        </div>
        <div class="tk-section">
          <div class="tk-section-title">其他配置</div>
          <el-form-item label="宿主机组">
            <div class="bind-selector-row">
              <el-input :model-value="formData.host_group_id ? `宿主机组 #${formData.host_group_id}${formData._groupName ? ' - ' + formData._groupName : ''}` : '未选择'" disabled style="flex: 1" />
              <el-button type="primary" @click="showHostGroupSelector = true" style="margin-left: 8px">选择</el-button>
              <el-button v-if="formData.host_group_id" @click="formData.host_group_id = 0; formData._groupName = ''" style="margin-left: 4px">清除</el-button>
            </div>
          </el-form-item>
          <el-form-item label="介绍">
            <el-input v-model="formData.description" type="textarea" :rows="3" placeholder="宿主机介绍（可选）" />
          </el-form-item>
        </div>
      </el-form>
      <template #footer>
        <div class="tk-dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" :loading="submitLoading" @click="handleSubmit">确定</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 宿主机组选择器 -->
    <HostGroupSelectorPopup
      v-model="showHostGroupSelector"
      :service-id="serviceId"
      :current-id="formData.host_group_id"
      @confirm="handleHostGroupSelected"
    />

    <!-- 详情弹窗 -->
    <el-dialog v-model="detailVisible" title="宿主机详情" width="680px" destroy-on-close>
      <el-descriptions :column="2" border v-if="currentDetail" v-loading="detailLoading">
        <el-descriptions-item label="ID">{{ currentDetail.id }}</el-descriptions-item>
        <el-descriptions-item label="名称">{{ currentDetail.name }}</el-descriptions-item>
        <el-descriptions-item label="IP">{{ currentDetail.ip || '-' }}</el-descriptions-item>
        <el-descriptions-item label="服务地址">{{ currentDetail.base_url || '-' }}</el-descriptions-item>
        <el-descriptions-item label="SSH 端口">{{ currentDetail.port || '-' }}</el-descriptions-item>
        <el-descriptions-item label="SSH 用户">{{ currentDetail.user || '-' }}</el-descriptions-item>
        <el-descriptions-item label="宿主机组">{{ getGroupName(currentDetail.host_group_id) }}</el-descriptions-item>
        <el-descriptions-item label="状态">
          <el-tag :type="currentDetail.is_active ? 'success' : 'danger'" size="small">{{ currentDetail.is_active ? '启用' : '禁用' }}</el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="认证Token" :span="2">
          <el-input v-if="currentDetail.token" :model-value="currentDetail.token" readonly show-password style="max-width: 300px" />
          <span v-else class="text-muted">未设置</span>
        </el-descriptions-item>
        <el-descriptions-item label="SSH 密码">
          <el-input v-if="currentDetail.password" :model-value="currentDetail.password" readonly show-password style="max-width: 200px" />
          <span v-else class="text-muted">未设置</span>
        </el-descriptions-item>
        <el-descriptions-item label="SSH 私钥">{{ currentDetail.private_key ? '已配置' : '未设置' }}</el-descriptions-item>
        <el-descriptions-item label="最大CPU">{{ currentDetail.max_cpu ? currentDetail.max_cpu + ' 核' : '-' }}</el-descriptions-item>
        <el-descriptions-item label="最大内存">{{ formatMemKB(currentDetail.max_memory) }}</el-descriptions-item>
        <el-descriptions-item label="最大磁盘">{{ formatDiskGB(currentDetail.max_disk) }}</el-descriptions-item>
        <el-descriptions-item label="带宽">↓{{ currentDetail.rx_bandwidth || 0 }} Mbps / ↑{{ currentDetail.tx_bandwidth || 0 }} Mbps</el-descriptions-item>
        <el-descriptions-item label="介绍" :span="2">{{ currentDetail.description || '-' }}</el-descriptions-item>
        <el-descriptions-item label="创建时间">{{ formatTimestamp(currentDetail.created_at) }}</el-descriptions-item>
        <el-descriptions-item label="更新时间">{{ formatTimestamp(currentDetail.updated_at) }}</el-descriptions-item>
      </el-descriptions>
      <template #footer>
        <el-button @click="detailVisible = false">关闭</el-button>
      </template>
    </el-dialog>

    <!-- 创建注册令牌弹窗 -->
    <el-dialog v-model="tokenDialogVisible" title="创建宿主机注册令牌" width="700px" destroy-on-close class="token-dialog">
      <el-form ref="tokenFormRef" :model="tokenForm" :rules="tokenRules" label-width="120px">
        <div class="tk-section">
          <div class="tk-section-title">基本信息</div>
          <el-form-item label="宿主机名称" prop="name">
            <el-input v-model="tokenForm.name" placeholder="为该宿主机命名" />
          </el-form-item>
          <el-form-item label="所属宿主机组" prop="host_group_id">
            <div class="bind-selector-row">
              <el-input
                :model-value="tokenForm.host_group_id ? `宿主机组 #${tokenForm.host_group_id}${tokenForm._groupName ? ' - ' + tokenForm._groupName : ''}` : ''"
                placeholder="请选择宿主机组" disabled style="flex: 1" />
              <el-button type="primary" @click="showTokenGroupSelector = true" style="margin-left: 8px">选择</el-button>
              <el-button v-if="tokenForm.host_group_id" @click="tokenForm.host_group_id = 0; tokenForm._groupName = ''" style="margin-left: 4px">清除</el-button>
            </div>
          </el-form-item>
          <el-form-item label="宿主机描述">
            <el-input v-model="tokenForm.description" type="textarea" :rows="2" placeholder="宿主机描述（可选）" />
          </el-form-item>
        </div>
        <div class="tk-section">
          <div class="tk-section-title">资源配额</div>
          <div class="tk-resource-grid">
            <el-form-item label="CPU" prop="max_cpu" class="tk-res-item">
              <el-input-number v-model="tokenForm.max_cpu" :min="1" controls-position="right" /><span class="tk-res-unit">核</span>
            </el-form-item>
            <el-form-item label="内存" prop="max_memory" class="tk-res-item">
              <el-input-number v-model="tokenMemDisplay" :min="0" controls-position="right" />
              <el-select v-model="tokenMemUnit" class="tk-unit-select">
                <el-option v-for="u in memoryUnitOptions" :key="u.label" :label="u.label" :value="u.label" />
              </el-select>
            </el-form-item>
            <el-form-item label="磁盘" prop="max_disk" class="tk-res-item">
              <el-input-number v-model="tokenDiskDisplay" :min="0" controls-position="right" />
              <el-select v-model="tokenDiskUnit" class="tk-unit-select">
                <el-option v-for="u in diskUnitOptions" :key="u.label" :label="u.label" :value="u.label" />
              </el-select>
            </el-form-item>
            <el-form-item label="下行带宽" class="tk-res-item">
              <el-input-number v-model="tokenForm.rx_bandwidth" :min="0" controls-position="right" /><span class="tk-res-unit">Mbps</span>
            </el-form-item>
            <el-form-item label="上行带宽" class="tk-res-item">
              <el-input-number v-model="tokenForm.tx_bandwidth" :min="0" controls-position="right" /><span class="tk-res-unit">Mbps</span>
            </el-form-item>
          </div>
        </div>
        <div class="tk-section">
          <div class="tk-section-title clickable" @click="showTokenDiskIo = !showTokenDiskIo">
            硬盘 IO 限制
            <el-icon class="section-arrow" :class="{ expanded: showTokenDiskIo }"><ArrowRight /></el-icon>
            <span class="section-hint">可选，不展开则使用默认值</span>
          </div>
          <div v-show="showTokenDiskIo">
            <div class="io-sub-title">
              带宽限制
              <el-select v-model="tokenIoBwUnit" class="tk-unit-select" style="width: 90px; margin-left: 8px">
                <el-option v-for="u in ioBwUnitOptions" :key="u.label" :label="u.label" :value="u.label" />
              </el-select>
            </div>
            <div class="tk-resource-grid">
              <el-form-item v-for="f in diskIoBwFields" :key="f.key" :label="f.label" class="tk-res-item">
                <el-input-number :model-value="+(tokenForm[f.key] / getTokenIoBwFactor()).toFixed(2)" @update:model-value="v => tokenForm[f.key] = Math.round((v || 0) * getTokenIoBwFactor())" :min="0" controls-position="right" />
              </el-form-item>
            </div>
            <div class="io-sub-title">IOPS 限制</div>
            <div class="tk-resource-grid">
              <el-form-item v-for="f in diskIoIopsFields" :key="f.key" :label="f.label" class="tk-res-item">
                <el-input-number v-model="tokenForm[f.key]" :min="0" controls-position="right" />
              </el-form-item>
            </div>
          </div>
        </div>
        <div class="tk-section">
          <div class="tk-section-title">令牌有效期</div>
          <el-form-item label="有效期" prop="expire_hours">
            <el-input-number v-model="tokenForm.expire_hours" :min="1" :max="8760" controls-position="right" style="width: 100%" />
            <div class="form-hint">单位：小时。默认 24 小时，最大 8760 小时（365天）</div>
          </el-form-item>
        </div>
      </el-form>
      <template #footer>
        <div class="tk-dialog-footer">
          <el-button @click="tokenDialogVisible = false">取消</el-button>
          <el-button type="primary" :loading="tokenSubmitLoading" @click="handleTokenSubmit">
            <el-icon><Key /></el-icon>创建令牌
          </el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 令牌结果弹窗 -->
    <el-dialog v-model="tokenResultVisible" title="注册令牌已生成" width="560px" :close-on-click-modal="false" class="token-result-dialog">
      <div class="tk-result-wrapper">
        <div class="tk-result-header">
          <el-icon class="tk-result-icon"><Key /></el-icon>
          <div>
            <div class="tk-result-name">{{ tokenResultInfo.name }}</div>
            <div class="tk-result-meta">有效期 {{ tokenResultInfo.expire_hours }} 小时</div>
          </div>
        </div>
        <el-alert type="warning" :closable="false" show-icon style="margin-bottom: 16px">
          <template #title>请立即复制并保存此令牌，关闭后将无法再次查看</template>
        </el-alert>
        <div class="tk-token-block">
          <div class="tk-token-label">后端地址</div>
          <div class="tk-token-value">{{ baseUrl }}</div>
        </div>
        <div class="tk-token-block">
          <div class="tk-token-label">service_id（主控服务ID）</div>
          <div class="tk-token-value">{{ tokenResultInfo.service_id }}</div>
        </div>
        <div class="tk-token-block">
          <div class="tk-token-label">注册令牌</div>
          <div class="tk-token-value">{{ tokenResultInfo.token }}</div>
        </div>
        <el-button type="primary" class="tk-copy-btn" @click="copyToken">
          <el-icon><CopyDocument /></el-icon>复制令牌到剪贴板
        </el-button>
      </div>
      <template #footer>
        <el-button @click="tokenResultVisible = false">关闭</el-button>
      </template>
    </el-dialog>

    <!-- 令牌用宿主机组选择器 -->
    <HostGroupSelectorPopup
      v-model="showTokenGroupSelector"
      :service-id="serviceId"
      :current-id="tokenForm.host_group_id"
      @confirm="handleTokenGroupSelected"
    />

    <!-- 指标弹窗 -->
    <el-dialog v-model="metricsVisible" title="宿主机指标" width="700px" destroy-on-close>
      <div v-loading="metricsLoading">
        <template v-if="metricsData">
          <div class="metrics-time">数据时间：{{ formatBucket(metricsData.bucket) }}</div>
          <!-- CPU -->
          <el-card shadow="never" class="metrics-card">
            <template #header><span class="metrics-title"><el-icon><Monitor /></el-icon> CPU</span></template>
            <el-descriptions :column="2" border size="small">
              <el-descriptions-item label="使用率">{{ (metricsData.cpu_usage ?? 0).toFixed(1) }}%</el-descriptions-item>
              <el-descriptions-item label="核心数">{{ metricsData.cpu_count ?? '-' }}</el-descriptions-item>
            </el-descriptions>
          </el-card>
          <!-- 内存 -->
          <el-card shadow="never" class="metrics-card">
            <template #header><span class="metrics-title"><el-icon><Coin /></el-icon> 内存</span></template>
            <el-descriptions :column="2" border size="small">
              <el-descriptions-item label="总计">{{ formatBytesRaw(metricsData.mem_total) }}</el-descriptions-item>
              <el-descriptions-item label="已用">{{ formatBytesRaw(metricsData.mem_used) }}</el-descriptions-item>
              <el-descriptions-item label="空闲">{{ formatBytesRaw(metricsData.mem_free) }}</el-descriptions-item>
              <el-descriptions-item label="使用率">{{ (metricsData.mem_percent ?? 0).toFixed(1) }}%</el-descriptions-item>
            </el-descriptions>
          </el-card>
          <!-- 网络 -->
          <el-card shadow="never" class="metrics-card">
            <template #header><span class="metrics-title"><el-icon><Connection /></el-icon> 网络</span></template>
            <el-descriptions :column="2" border size="small">
              <el-descriptions-item label="公网接收速率">{{ formatNetSpeed(metricsData.inet_rx) }}</el-descriptions-item>
              <el-descriptions-item label="公网发送速率">{{ formatNetSpeed(metricsData.inet_tx) }}</el-descriptions-item>
              <el-descriptions-item label="内网接收(累积)">{{ formatBytesRaw(metricsData.net_rx) }}</el-descriptions-item>
              <el-descriptions-item label="内网发送(累积)">{{ formatBytesRaw(metricsData.net_tx) }}</el-descriptions-item>
            </el-descriptions>
          </el-card>
        </template>
        <el-empty v-else description="暂无指标数据" />
      </div>
      <template #footer>
        <el-button @click="metricsVisible = false">关闭</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, computed, inject, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Refresh, Search, ArrowLeft, ArrowRight, Monitor, Coin, Connection, Key, CopyDocument } from '@element-plus/icons-vue'
import {
  getRemoteHostList, getRemoteHostDetail,
  addRemoteHost, updateRemoteHost, deleteRemoteHost,
  getHostGroupList, createHostToken, getMetricsHistory
} from '@/api/admin/kvmService'
import { extractApiError } from '@/utils/kvmErrorUtil'
import { baseUrl } from '@/config/env'
import HostGroupSelectorPopup from '@/components/admin/HostGroupSelectorPopup.vue'

const route = useRoute()
const router = useRouter()
const embedded = inject('embedded', false)
const injectedServiceId = inject('serviceId', null)
const injectedServiceName = inject('serviceName', null)
const serviceId = computed(() => injectedServiceId?.value || parseInt(route.query.service_id) || 0)
const serviceName = computed(() => injectedServiceName?.value || route.query.service_name || '')

const loading = ref(false)
const submitLoading = ref(false)
const detailLoading = ref(false)
const metricsLoading = ref(false)
const hostList = ref([])
const total = ref(0)
const keyword = ref('')
const filterGroupId = ref('')
const hostGroupOptions = ref([])
const showHostGroupSelector = ref(false)

const queryParams = reactive({ page: 1, page_size: 10, keyword: '', host_group_id: '' })

// 弹窗
const dialogVisible = ref(false)
const dialogType = ref('add')
const formRef = ref(null)
const detailVisible = ref(false)
const currentDetail = ref(null)
const metricsVisible = ref(false)
const metricsData = ref(null)

const diskIoDefaults = {
  read_bytes_sec: 314572800, write_bytes_sec: 314572800,
  read_iops_sec: 1000, write_iops_sec: 1000,
  read_bytes_sec_max: 314572800, write_bytes_sec_max: 314572800,
  read_iops_sec_max: 1000, write_iops_sec_max: 1000
}
const diskIoBwFields = [
  { key: 'read_bytes_sec', label: '读取' },
  { key: 'write_bytes_sec', label: '写入' },
  { key: 'read_bytes_sec_max', label: '突发读取' },
  { key: 'write_bytes_sec_max', label: '突发写入' }
]
const diskIoIopsFields = [
  { key: 'read_iops_sec', label: '读取' },
  { key: 'write_iops_sec', label: '写入' },
  { key: 'read_iops_sec_max', label: '突发读取' },
  { key: 'write_iops_sec_max', label: '突发写入' }
]
const diskIoFields = [
  ...diskIoBwFields.map(f => ({ ...f, isBandwidth: true })),
  ...diskIoIopsFields.map(f => ({ ...f, isBandwidth: false }))
]
const ioBwUnitOptions = [
  { label: 'B/s', factor: 1 },
  { label: 'KB/s', factor: 1024 },
  { label: 'MB/s', factor: 1048576 },
  { label: 'GB/s', factor: 1073741824 }
]
const ioBwUnit = ref('MB/s')
const tokenIoBwUnit = ref('MB/s')
const getIoBwFactor = () => ioBwUnitOptions.find(u => u.label === ioBwUnit.value)?.factor || 1048576
const getTokenIoBwFactor = () => ioBwUnitOptions.find(u => u.label === tokenIoBwUnit.value)?.factor || 1048576

const showDiskIoSection = ref(false)
const showTokenDiskIo = ref(false)

const formData = reactive({
  id: undefined, name: '', base_url: '', ip: '', token: '',
  port: 22, user: '', password: '', private_key: '',
  max_cpu: 0, max_memory: 0, max_disk: 0,
  rx_bandwidth: 0, tx_bandwidth: 0, host_group_id: 0, description: '',
  _groupName: '',
  ...diskIoDefaults
})

const formRules = {
  name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
  base_url: [{ required: true, message: '请输入服务地址', trigger: 'blur' }],
  ip: [{ required: true, message: '请输入 IP 地址', trigger: 'blur' }]
}

const formatMemKB = (val) => {
  if (!val) return '-'; val = Number(val)
  if (val >= 1073741824) return (val / 1073741824).toFixed(1) + ' TB'
  if (val >= 1048576) return (val / 1048576).toFixed(1) + ' GB'
  if (val >= 1024) return (val / 1024).toFixed(1) + ' MB'
  return val + ' KB'
}

const formatDiskGB = (val) => {
  if (!val) return '-'; val = Number(val)
  if (val >= 1024) return (val / 1024).toFixed(1) + ' TB'
  return val.toFixed(1) + ' GB'
}

const memoryUnit = ref('GB')
const diskUnit = ref('GB')
const memoryUnitOptions = [
  { label: 'KB', factor: 1 },
  { label: 'MB', factor: 1024 },
  { label: 'GB', factor: 1048576 },
  { label: 'TB', factor: 1073741824 }
]
const diskUnitOptions = [
  { label: 'GB', factor: 1 },
  { label: 'TB', factor: 1024 }
]
const getMemFactor = () => memoryUnitOptions.find(u => u.label === memoryUnit.value)?.factor || 1048576
const getDiskFactor = () => diskUnitOptions.find(u => u.label === diskUnit.value)?.factor || 1

const memoryDisplay = computed({
  get: () => formData.max_memory ? +(formData.max_memory / getMemFactor()).toFixed(2) : 0,
  set: (v) => { formData.max_memory = Math.round((v || 0) * getMemFactor()) }
})
const diskDisplay = computed({
  get: () => formData.max_disk ? +(formData.max_disk / getDiskFactor()).toFixed(2) : 0,
  set: (v) => { formData.max_disk = Math.round((v || 0) * getDiskFactor()) }
})

/** 格式化原始字节 */
const formatBytesRaw = (val) => {
  if (!val && val !== 0) return '-'
  val = Number(val)
  if (val >= 1099511627776) return (val / 1099511627776).toFixed(2) + ' TB'
  if (val >= 1073741824) return (val / 1073741824).toFixed(2) + ' GB'
  if (val >= 1048576) return (val / 1048576).toFixed(2) + ' MB'
  if (val >= 1024) return (val / 1024).toFixed(1) + ' KB'
  return val + ' B'
}

const formatBucket = (bucket) => {
  if (!bucket) return '-'
  const d = new Date(bucket)
  return isNaN(d.getTime()) ? String(bucket) : d.toLocaleString('zh-CN')
}

const formatNetSpeed = (v) => {
  if (!v && v !== 0) return '0 B/s'
  v = Number(v)
  if (v >= 1073741824) return (v / 1073741824).toFixed(1) + ' GB/s'
  if (v >= 1048576) return (v / 1048576).toFixed(1) + ' MB/s'
  if (v >= 1024) return (v / 1024).toFixed(1) + ' KB/s'
  return v.toFixed(0) + ' B/s'
}

/** 格式化后端 {seconds, nanos} 时间戳 */
const formatTimestamp = (ts) => {
  if (!ts) return '-'
  if (typeof ts === 'object' && ts.seconds) {
    const d = new Date(Number(ts.seconds) * 1000)
    return d.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' })
  }
  if (typeof ts === 'string' || typeof ts === 'number') {
    const d = new Date(ts)
    return isNaN(d.getTime()) ? String(ts) : d.toLocaleString('zh-CN')
  }
  return '-'
}

const getGroupName = (gid) => {
  if (!gid) return '-'
  const g = hostGroupOptions.value.find(x => x.id === gid)
  return g ? `${g.name} (#${gid})` : `#${gid}`
}

const resetForm = () => {
  Object.assign(formData, {
    id: undefined, name: '', base_url: '', ip: '', token: '',
    port: 22, user: '', password: '', private_key: '',
    max_cpu: 0, max_memory: 0, max_disk: 0,
    rx_bandwidth: 0, tx_bandwidth: 0, host_group_id: 0, description: '',
    _groupName: '', ...diskIoDefaults
  })
  showDiskIoSection.value = false
  ioBwUnit.value = 'MB/s'
}

const handleHostGroupSelected = (group) => {
  formData.host_group_id = group.id
  formData._groupName = group.name || ''
}

// 加载宿主机组选项
const loadHostGroupOptions = async () => {
  try {
    const res = await getHostGroupList({ service_id: serviceId.value })
    const body = res?.data
    if (body?.code === 200 && body?.data) {
      const items = Array.isArray(body.data) ? body.data : (body.data.data || [])
      hostGroupOptions.value = items.map(i => ({ id: i.Id ?? i.id, name: i.Name ?? i.name }))
    }
  } catch (e) { /* ignore */ }
}

// 加载列表
const loadList = async () => {
  if (!serviceId.value) return
  loading.value = true
  try {
    const params = { service_id: serviceId.value, page: queryParams.page, page_size: queryParams.page_size }
    if (keyword.value) params.keyword = keyword.value
    if (filterGroupId.value) params.host_group_id = filterGroupId.value
    const res = await getRemoteHostList(params)
    const body = res?.data
    if (body?.code === 200 && body?.data) {
      const inner = body.data
      const items = Array.isArray(inner) ? inner : (inner.hosts || inner.data || inner.list || [])
      hostList.value = items
      total.value = inner.total ?? inner.all_count ?? items.length
    } else {
      hostList.value = []
      total.value = 0
    }
  } catch (e) {
    console.error('获取宿主机列表失败:', e)
    ElMessage.error('获取宿主机列表失败')
  } finally {
    loading.value = false
  }
}

const handleSearch = () => { queryParams.page = 1; loadList() }
const handleSizeChange = (s) => { queryParams.page_size = s; queryParams.page = 1; loadList() }
const handlePageChange = (p) => { queryParams.page = p; loadList() }

const handleAdd = () => { dialogType.value = 'add'; resetForm(); dialogVisible.value = true }

const handleEdit = (row) => {
  dialogType.value = 'edit'
  // 先用列表数据回填，密码需从详情取
  Object.assign(formData, {
    id: row.id, name: row.name, base_url: row.base_url, ip: row.ip, token: row.token || '',
    port: row.port || 22, user: row.user || '', password: row.password || '', private_key: row.private_key || '',
    max_cpu: row.max_cpu || 0, max_memory: row.max_memory || 0, max_disk: row.max_disk || 0,
    rx_bandwidth: row.rx_bandwidth || 0, tx_bandwidth: row.tx_bandwidth || 0,
    host_group_id: row.host_group_id || 0, description: row.description || '',
    _groupName: getGroupName(row.host_group_id),
    ...Object.fromEntries(diskIoFields.map(f => [f.key, row[f.key] ?? diskIoDefaults[f.key]]))
  })
  showDiskIoSection.value = diskIoFields.some(f => row[f.key] && row[f.key] !== diskIoDefaults[f.key])
  getRemoteHostDetail({ service_id: serviceId.value, id: row.id }).then(res => {
    const body = res?.data
    if (body?.code === 200 && body?.data) {
      const detail = body.data.host ?? body.data.data ?? body.data
      if (detail.password) formData.password = detail.password
      if (detail.token) formData.token = detail.token
      if (detail.private_key) formData.private_key = detail.private_key
      diskIoFields.forEach(f => { if (detail[f.key] !== undefined) formData[f.key] = detail[f.key] })
    }
  }).catch(() => {})
  dialogVisible.value = true
}

const handleSubmit = () => {
  formRef.value?.validate(async (valid) => {
    if (!valid) return
    submitLoading.value = true
    try {
      const payload = { ...formData, service_id: serviceId.value }
      delete payload.id
      delete payload._groupName
      // 可选参数为空时不提交
      if (!payload.token) delete payload.token
      if (!payload.password) delete payload.password
      if (!payload.private_key) delete payload.private_key
      if (!payload.description) delete payload.description
      if (!payload.host_group_id) delete payload.host_group_id
      let res
      if (dialogType.value === 'add') {
        res = await addRemoteHost(payload)
      } else {
        payload.id = formData.id
        res = await updateRemoteHost(payload)
      }
      const body = res?.data
      if (body?.code === 200) {
        ElMessage.success(dialogType.value === 'add' ? '新增成功' : '修改成功')
        dialogVisible.value = false
        loadList()
      } else {
        ElMessage.error(extractApiError(body, '操作失败'))
      }
    } catch (e) {
      ElMessage.error(extractApiError(e?.response?.data, '操作失败'))
    } finally {
      submitLoading.value = false
    }
  })
}

const handleViewDetail = async (row) => {
  detailVisible.value = true
  detailLoading.value = true
  currentDetail.value = null
  try {
    const res = await getRemoteHostDetail({ service_id: serviceId.value, id: row.id })
    const body = res?.data
    if (body?.code === 200 && body?.data) {
      // API返回 data.host 嵌套
      currentDetail.value = body.data.host ?? body.data.data ?? body.data
    } else {
      currentDetail.value = row
    }
  } catch (e) {
    currentDetail.value = row
  } finally {
    detailLoading.value = false
  }
}

const handleMetrics = async (row) => {
  metricsVisible.value = true
  metricsLoading.value = true
  metricsData.value = null
  try {
    const now = new Date()
    const start = new Date(now.getTime() - 60 * 60 * 1000)
    const res = await getMetricsHistory({
      service_id: serviceId.value,
      host_id: row.id,
      start: start.toISOString(),
      end_time: now.toISOString(),
      interval: '1m'
    })
    const body = res?.data
    if (body?.code === 200 && body?.data) {
      const arr = Array.isArray(body.data) ? body.data : (body.data.data || [])
      metricsData.value = arr.length ? arr[arr.length - 1] : null
      if (!metricsData.value) ElMessage.warning('暂无指标数据')
    } else {
      ElMessage.warning('暂无指标数据')
    }
  } catch (e) {
    ElMessage.error('获取指标失败')
  } finally {
    metricsLoading.value = false
  }
}

const handleGoDetail = (row) => {
  router.push({ path: '/virtualization/host-detail', query: { service_id: serviceId.value, service_name: serviceName.value, id: row.id } })
}

const handleDelete = (row) => {
  ElMessageBox.confirm(`确定要删除宿主机「${row.name}」吗？`, '删除确认', {
    confirmButtonText: '确定删除', cancelButtonText: '取消', type: 'warning'
  }).then(async () => {
    try {
      const res = await deleteRemoteHost({ service_id: serviceId.value, id: row.id })
      const body = res?.data
      if (body?.code === 200) { ElMessage.success('删除成功'); loadList() }
      else ElMessage.error(extractApiError(body, '删除失败'))
    } catch (e) {
      ElMessage.error(extractApiError(e?.response?.data, '删除失败'))
    }
  }).catch(() => {})
}

// ========== 创建注册令牌 ==========
const tokenDialogVisible = ref(false)
const tokenSubmitLoading = ref(false)
const tokenResultVisible = ref(false)
const showTokenGroupSelector = ref(false)
const tokenFormRef = ref(null)
const tokenMemUnit = ref('GB')
const tokenDiskUnit = ref('GB')

const tokenForm = reactive({
  name: '', host_group_id: 0, max_cpu: 4,
  max_memory: 4194304, max_disk: 100,
  rx_bandwidth: 100, tx_bandwidth: 100,
  description: '', expire_hours: 24,
  _groupName: '',
  ...diskIoDefaults
})

const tokenResultInfo = reactive({ name: '', expire_hours: 24, token: '', service_id: 0 })

const tokenRules = {
  name: [{ required: true, message: '请输入宿主机名称', trigger: 'blur' }],
  host_group_id: [{ required: true, type: 'number', min: 1, message: '请选择宿主机组', trigger: 'change' }],
  max_cpu: [{ required: true, type: 'number', min: 1, message: '请设置最大CPU核数', trigger: 'change' }],
  max_memory: [{ required: true, type: 'number', min: 1, message: '请设置最大内存', trigger: 'change' }],
  max_disk: [{ required: true, type: 'number', min: 1, message: '请设置最大磁盘', trigger: 'change' }],
  expire_hours: [{ required: true, type: 'number', min: 1, message: '请设置有效期', trigger: 'change' }]
}

const getTokenMemFactor = () => memoryUnitOptions.find(u => u.label === tokenMemUnit.value)?.factor || 1048576
const getTokenDiskFactor = () => diskUnitOptions.find(u => u.label === tokenDiskUnit.value)?.factor || 1

const tokenMemDisplay = computed({
  get: () => tokenForm.max_memory ? +(tokenForm.max_memory / getTokenMemFactor()).toFixed(2) : 0,
  set: (v) => { tokenForm.max_memory = Math.round((v || 0) * getTokenMemFactor()) }
})
const tokenDiskDisplay = computed({
  get: () => tokenForm.max_disk ? +(tokenForm.max_disk / getTokenDiskFactor()).toFixed(2) : 0,
  set: (v) => { tokenForm.max_disk = Math.round((v || 0) * getTokenDiskFactor()) }
})

const openTokenDialog = () => {
  Object.assign(tokenForm, {
    name: '', host_group_id: 0, max_cpu: 4,
    max_memory: 4194304, max_disk: 100,
    rx_bandwidth: 100, tx_bandwidth: 100,
    description: '', expire_hours: 24, _groupName: '',
    ...diskIoDefaults
  })
  tokenMemUnit.value = 'GB'
  tokenDiskUnit.value = 'GB'
  showTokenDiskIo.value = false
  tokenIoBwUnit.value = 'MB/s'
  tokenDialogVisible.value = true
}

const handleTokenGroupSelected = (group) => {
  tokenForm.host_group_id = group.id
  tokenForm._groupName = group.name || ''
}

const handleTokenSubmit = () => {
  tokenFormRef.value?.validate(async (valid) => {
    if (!valid) return
    tokenSubmitLoading.value = true
    try {
      const fd = new FormData()
      fd.append('service_id', serviceId.value)
      fd.append('name', tokenForm.name)
      fd.append('host_group_id', tokenForm.host_group_id)
      fd.append('max_cpu', tokenForm.max_cpu)
      fd.append('max_memory', tokenForm.max_memory)
      fd.append('max_disk', tokenForm.max_disk)
      fd.append('rx_bandwidth', tokenForm.rx_bandwidth)
      fd.append('tx_bandwidth', tokenForm.tx_bandwidth)
      diskIoFields.forEach(f => { if (tokenForm[f.key] !== undefined) fd.append(f.key, tokenForm[f.key]) })
      fd.append('description', tokenForm.description || '')
      fd.append('expire_hours', tokenForm.expire_hours)

      const res = await createHostToken(fd)
      const body = res?.data
      if (body?.code === 200 && body?.data) {
        const data = body.data
        tokenResultInfo.name = tokenForm.name
        tokenResultInfo.expire_hours = tokenForm.expire_hours
        tokenResultInfo.token = data.token || data.Token || JSON.stringify(data)
        tokenResultInfo.service_id = serviceId.value
        tokenDialogVisible.value = false
        tokenResultVisible.value = true
        ElMessage.success('注册令牌创建成功')
      } else {
        ElMessage.error(extractApiError(body, '创建令牌失败'))
      }
    } catch (e) {
      ElMessage.error(extractApiError(e?.response?.data, '创建令牌失败'))
    } finally {
      tokenSubmitLoading.value = false
    }
  })
}

const copyToken = async () => {
  const text = `后端地址：${baseUrl}\nservice_id：${tokenResultInfo.service_id}\n注册令牌：${tokenResultInfo.token}`
  try {
    await navigator.clipboard.writeText(text)
    ElMessage.success('令牌信息已复制到剪贴板')
  } catch {
    const textarea = document.createElement('textarea')
    textarea.value = text
    document.body.appendChild(textarea)
    textarea.select()
    document.execCommand('copy')
    document.body.removeChild(textarea)
    ElMessage.success('令牌信息已复制到剪贴板')
  }
}

const goBack = () => { router.push('/virtualization/kvm-service') }

onMounted(() => {
  if (serviceId.value) { loadList(); loadHostGroupOptions() }
})
</script>

<style scoped>
.host-manage-container { padding: 20px; }
.host-addr { font-family: 'Consolas', monospace; color: #409eff; font-size: 13px; }
.host-url { font-size: 12px; color: #909399; margin-top: 2px; }
.metrics-time { font-size: 12px; color: #86909c; margin-bottom: 12px; }
.metrics-card { margin-bottom: 12px; }
.metrics-title { font-weight: 600; font-size: 14px; display: inline-flex; align-items: center; gap: 6px; }
.metrics-title .el-icon { font-size: 16px; color: #409eff; }
.tk-section-title.clickable { cursor: pointer; user-select: none; display: flex; align-items: center; gap: 6px; }
.tk-section-title.clickable:hover { color: #409eff; }
.section-arrow { transition: transform 0.2s; font-size: 14px; }
.section-arrow.expanded { transform: rotate(90deg); }
.section-hint { font-size: 12px; color: #909399; font-weight: 400; }
.io-sub-title { font-size: 13px; font-weight: 500; color: #606266; margin: 12px 0 8px; display: flex; align-items: center; }
</style>
