<template>
  <div class="dev-page">
    <!-- 工具栏 -->
    <div class="page-toolbar">
      <div class="toolbar-left">
        <h3 class="page-title">服务器管理</h3>
        <a-tag color="blue">{{ list.length }} 台</a-tag>
        <a-select
          v-model:value="selectedAppId"
          placeholder="全部应用"
          allow-clear
          style="width: 180px"
          @change="loadList"
        >
          <a-select-option v-for="app in appOptions" :key="app.productId" :value="app.productId">
            {{ app.productName }}
          </a-select-option>
        </a-select>
      </div>
      <div class="toolbar-right">
        <a-input-search
          v-model:value="searchText"
          placeholder="搜索名称 / IP"
          style="width: 200px"
          allow-clear
          @search="loadList"
        />
        <PermissionGuard :app-id="selectedAppId" permission="canEditResource" :show-tip="true">
          <a-button type="primary" @click="showAdd = true">
            <template #icon><PlusOutlined /></template>
            添加服务器
          </a-button>
        </PermissionGuard>
      </div>
    </div>

    <!-- 服务器卡片列表 -->
    <div v-if="loading" class="card-loading">
      <a-spin size="large" />
    </div>
    <div v-else-if="list.length === 0" class="card-empty">
      <a-empty description="暂无服务器">
        <template v-if="!selectedAppId || getAppPermission(selectedAppId)?.canEditResource">
          <a-button type="primary" @click="showAdd = true">
            <template #icon><PlusOutlined /></template>
            添加服务器
          </a-button>
        </template>
      </a-empty>
    </div>
    <div v-else class="server-grid">
      <div
        v-for="item in list"
        :key="item.resourceId"
        class="server-card"
        :class="{ 'card-expired': item.status === 'expired' }"
      >
        <!-- 卡片头部 -->
        <div class="card-header">
          <div class="card-header-left">
            <div class="server-name">{{ item.name }}</div>
            <a-badge
              :status="item.status === 'running' ? 'success' : item.status === 'stopped' ? 'default' : 'warning'"
              :text="statusLabel[item.status] || item.status"
            />
          </div>
          <a-dropdown :trigger="['click']">
            <a-button type="text" size="small">
              <template #icon><EllipsisOutlined /></template>
            </a-button>
            <template #overlay>
              <a-menu @click="({ key }: any) => handleMenuAction(key, item)">
                <a-menu-item v-if="item.isOwner || getAppPermission(item.appId)?.canEditResource" key="edit">
                  <template #icon><EditOutlined />编辑</template>
                </a-menu-item>
                <a-menu-item v-if="item.sshUsername && (item.accessLevel ?? 1) >= 2" key="ssh">
                  <template #icon><CodeOutlined />SSH 连接</template>
                </a-menu-item>
                <a-menu-item v-if="item.panelPort && (item.accessLevel ?? 1) >= 2" key="panel">
                  <template #icon><DashboardOutlined />1Panel 面板</template>
                </a-menu-item>
                <a-menu-divider v-if="item.isOwner || getAppPermission(item.appId)?.canEditResource" />
                <a-menu-item v-if="item.isOwner || getAppPermission(item.appId)?.canEditResource" key="delete" danger>
                  <template #icon><DeleteOutlined />移除</template>
                </a-menu-item>
              </a-menu>
            </template>
          </a-dropdown>
        </div>

        <!-- 卡片信息区 -->
        <div class="card-info">
          <div class="info-row">
            <span class="info-label"><GlobalOutlined /></span>
            <span class="info-value ip-value" @click="copyText(item.ip!)">{{ item.ip }}</span>
          </div>
          <div v-if="item.provider" class="info-row">
            <span class="info-label"><CloudOutlined /></span>
            <span class="info-value">{{ providerLabel[item.provider!] || item.provider }}</span>
            <span v-if="item.appName" class="info-extra">{{ item.appName }}</span>
          </div>
          <!-- 连接信息：权限 >= 2 可见用户名 -->
          <div v-if="item.sshUsername && (item.accessLevel ?? 1) >= 2" class="info-row">
            <span class="info-label"><CodeOutlined /></span>
            <span class="info-value">{{ item.sshUsername }}@{{ item.ip }}</span>
          </div>
          <div v-if="item.expireAt" class="info-row">
            <span class="info-label"><ClockCircleOutlined /></span>
            <span class="info-value" :class="{ 'text-danger': isExpiringSoon(item.expireAt) }">{{ item.expireAt }}</span>
          </div>
          <!-- 权限提示：非 Owner 时显示 -->
          <div v-if="!item.isOwner" class="info-row access-hint">
            <LockOutlined style="color: #faad14; font-size: 12px;" />
            <span class="access-hint-text">{{ (item.accessLevel ?? 1) >= 2 ? '协作者（开发者）' : '协作者（只读）' }}</span>
          </div>
        </div>

        <!-- 端口概览 -->
        <div class="card-ports">
          <a-tooltip title="SSH 端口">
            <a-tag>SSH:{{ item.sshPort || 22 }}</a-tag>
          </a-tooltip>
          <a-tooltip title="MySQL 端口">
            <a-tag color="orange">MySQL:{{ item.mysqlPort || 3306 }}</a-tag>
          </a-tooltip>
          <a-tooltip title="PostgreSQL 端口">
            <a-tag color="geekblue">PG:{{ item.pgPort || 5432 }}</a-tag>
          </a-tooltip>
          <a-tooltip v-if="item.panelPort" title="1Panel 端口">
            <a-tag color="purple">Panel:{{ item.panelPort }}</a-tag>
          </a-tooltip>
        </div>

        <!-- 1Panel 状态信息（Owner 及 developer 角色可见） -->
        <div v-if="(item.accessLevel ?? 1) >= 2 && item.panelPort" class="card-status">
          <div class="status-header">
            <span class="status-title">运行状态</span>
            <a-button type="link" size="small" :loading="statusLoading[item.resourceId!]" @click="refreshStatus(item)">
              <template #icon><ReloadOutlined :spin="statusLoading[item.resourceId!]" /></template>
              {{ serverStatusMap[item.resourceId!] ? '刷新' : '获取' }}
            </a-button>
          </div>
          <div v-if="serverStatusMap[item.resourceId!]" class="status-content">
            <!-- 在线状态 -->
            <div class="status-online" :class="{ 'offline': serverStatusMap[item.resourceId!].online === 0 }">
              <span class="status-dot" :class="{ 'offline': serverStatusMap[item.resourceId!].online === 0 }"></span>
              <span>{{ serverStatusMap[item.resourceId!].online === 1 ? '在线' : '离线' }}</span>
              <span v-if="serverStatusMap[item.resourceId!].uptime" class="status-uptime">{{ serverStatusMap[item.resourceId!].uptime }}</span>
            </div>
            <!-- 资源使用条 -->
            <div class="status-bars">
              <div class="status-bar-item">
                <div class="status-bar-label">
                  <DesktopOutlined /> CPU
                  <span class="status-bar-value">{{ serverStatusMap[item.resourceId!].cpu }}%</span>
                </div>
                <a-progress :percent="Number(serverStatusMap[item.resourceId!].cpu)" :show-info="false" size="small" stroke-color="#1890ff" />
              </div>
              <div class="status-bar-item">
                <div class="status-bar-label">
                  <DatabaseFilled /> 内存
                  <span class="status-bar-value">{{ serverStatusMap[item.resourceId!].memory }}%</span>
                </div>
                <a-progress :percent="Number(serverStatusMap[item.resourceId!].memory)" :show-info="false" size="small" stroke-color="#722ed1" />
              </div>
              <div class="status-bar-item">
                <div class="status-bar-label">
                  <FolderOutlined /> 磁盘
                  <span class="status-bar-value">{{ serverStatusMap[item.resourceId!].disk }}%</span>
                </div>
                <a-progress :percent="Number(serverStatusMap[item.resourceId!].disk)" :show-info="false" size="small" stroke-color="#52c41a" />
              </div>
            </div>
          </div>
          <div v-else-if="statusErrorMap[item.resourceId!]" class="status-error">
            <ExclamationCircleOutlined /> {{ statusErrorMap[item.resourceId!] }}
          </div>
          <div v-else class="status-empty">
            点击「获取」查看服务器状态
          </div>
        </div>

        <!-- 卡片操作区 -->
        <div class="card-actions">
          <!-- 1Panel：需要有连接权限才能打开 -->
          <a-button
            v-if="item.panelPort && (item.accessLevel ?? 1) >= 2"
            type="primary"
            size="small"
            ghost
            @click="open1Panel(item)"
          >
            <template #icon><DashboardOutlined /></template>
            1Panel
          </a-button>
          <!-- SSH 连接：需要有连接权限（用户名可见） -->
          <a-button
            v-if="item.sshUsername && (item.accessLevel ?? 1) >= 2"
            size="small"
            @click="openSsh(item)"
          >
            <template #icon><CodeOutlined /></template>
            SSH
          </a-button>
          <!-- 编辑/删除：Owner 或应用有资源编辑权限 -->
          <a-button v-if="item.isOwner || getAppPermission(item.appId)?.canEditResource" size="small" @click="handleEdit(item)">
            <template #icon><EditOutlined /></template>
            编辑
          </a-button>
        </div>
      </div>
    </div>

    <!-- 添加/编辑弹窗 -->
    <a-modal
      v-model:open="showAdd"
      :title="editRecord ? '编辑服务器' : '添加服务器'"
      ok-text="保存"
      cancel-text="取消"
      :confirm-loading="saveLoading"
      width="580px"
      @ok="handleSave"
      @cancel="resetForm"
    >
      <a-form ref="formRef" :model="form" :rules="rules" layout="vertical" style="margin-top: 8px">
        <!-- 基本信息 -->
        <div class="form-section-header">
          <SettingOutlined />
          <span>基本信息</span>
        </div>
        <a-row :gutter="16">
          <a-col :span="14">
            <a-form-item label="服务器名称" name="name">
              <a-input v-model:value="form.name" placeholder="如：prod-server-01" />
            </a-form-item>
          </a-col>
          <a-col :span="10">
            <a-form-item label="IP 地址" name="ip">
              <a-input v-model:value="form.ip" placeholder="公网 IP" />
            </a-form-item>
          </a-col>
        </a-row>
        <a-row :gutter="16">
          <a-col :span="8">
            <a-form-item label="服务商" name="provider">
              <a-select v-model:value="form.provider" placeholder="请选择" allow-clear>
                <a-select-option value="tencent">腾讯云</a-select-option>
                <a-select-option value="aliyun">阿里云</a-select-option>
                <a-select-option value="huawei">华为云</a-select-option>
                <a-select-option value="other">其他</a-select-option>
              </a-select>
            </a-form-item>
          </a-col>
          <a-col :span="8">
            <a-form-item label="关联应用" name="appId">
              <a-select v-model:value="form.appId" placeholder="可选" allow-clear>
                <a-select-option v-for="app in appOptions" :key="app.productId" :value="app.productId">
                  {{ app.productName }}
                </a-select-option>
              </a-select>
            </a-form-item>
          </a-col>
          <a-col :span="8">
            <a-form-item label="到期时间" name="expireAt">
              <a-date-picker v-model:value="form.expireAt" value-format="YYYY-MM-DD" style="width: 100%" placeholder="可选" />
            </a-form-item>
          </a-col>
        </a-row>

        <!-- SSH 连接信息 -->
        <div class="form-section-header">
          <CodeOutlined />
          <span>SSH 连接</span>
          <a-button
            v-if="!editRecord"
            type="link"
            size="small"
            :loading="testingSsh"
            style="margin-left: auto"
            @click="handleTestSsh"
          >
            测试连接
          </a-button>
        </div>
        <a-row :gutter="16">
          <a-col :span="8">
            <a-form-item label="SSH 端口" name="sshPort">
              <a-input-number v-model:value="form.sshPort" :min="1" :max="65535" :precision="0" style="width: 100%" placeholder="22" />
            </a-form-item>
          </a-col>
          <a-col :span="8">
            <a-form-item label="用户名" name="sshUsername">
              <a-input v-model:value="form.sshUsername" placeholder="root" />
            </a-form-item>
          </a-col>
          <a-col :span="8">
            <a-form-item label="密码" name="sshPassword">
              <a-input-password v-model:value="form.sshPassword" placeholder="SSH 密码" />
            </a-form-item>
          </a-col>
        </a-row>

        <!-- 1Panel 面板 -->
        <div class="form-section-header">
          <DashboardOutlined />
          <span>1Panel 面板</span>
          <span class="form-section-hint">可选，填写后可一键打开面板</span>
        </div>
        <a-row :gutter="16">
          <a-col :span="8">
            <a-form-item label="面板端口" name="panelPort">
              <a-input-number v-model:value="form.panelPort" :min="1" :max="65535" :precision="0" style="width: 100%" placeholder="默认 8888" />
            </a-form-item>
          </a-col>
          <a-col :span="8">
            <a-form-item label="用户名" name="panelUsername">
              <a-input v-model:value="form.panelUsername" placeholder="面板登录用户名" />
            </a-form-item>
          </a-col>
          <a-col :span="8">
            <a-form-item label="密码" name="panelPassword">
              <a-input-password v-model:value="form.panelPassword" placeholder="面板登录密码" />
            </a-form-item>
          </a-col>
        </a-row>
        <a-row :gutter="16">
          <a-col :span="24">
            <a-form-item label="安全入口" name="panelPath">
              <a-input v-model:value="form.panelPath" placeholder="如 /abc123（1Panel 安全入口路径）" />
            </a-form-item>
          </a-col>
        </a-row>

        <!-- 数据库连接信息 -->
        <div class="form-section-header">
          <DatabaseOutlined />
          <span>数据库连接</span>
          <a-button
            v-if="!editRecord"
            type="link"
            size="small"
            :loading="testingConnection"
            style="margin-left: 4px"
            @click="handleTestConnection"
          >
            测试 MySQL
          </a-button>
          <a-button
            v-if="!editRecord"
            type="link"
            size="small"
            :loading="testingPgConnection"
            @click="handleTestPgConnection"
          >
            测试 PG
          </a-button>
        </div>
        <a-row :gutter="16">
          <a-col :span="8">
            <a-form-item label="MySQL 端口" name="mysqlPort">
              <a-input-number v-model:value="form.mysqlPort" :min="1" :max="65535" :precision="0" style="width: 100%" placeholder="3306" />
            </a-form-item>
          </a-col>
          <a-col :span="8">
            <a-form-item label="PG 端口" name="pgPort">
              <a-input-number v-model:value="form.pgPort" :min="1" :max="65535" :precision="0" style="width: 100%" placeholder="5432" />
            </a-form-item>
          </a-col>
        </a-row>
        <a-row :gutter="16">
          <a-col :span="12">
            <a-form-item label="管理员用户名" name="adminUsername">
              <a-input v-model:value="form.adminUsername" placeholder="如 root / postgres" />
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="管理员密码" name="adminPassword">
              <a-input-password v-model:value="form.adminPassword" placeholder="管理员密码（用于远程建库）" />
            </a-form-item>
          </a-col>
        </a-row>

        <!-- 备注 -->
        <a-form-item label="备注" name="remark" style="margin-bottom: 0">
          <a-textarea v-model:value="form.remark" :rows="2" placeholder="可选备注" />
        </a-form-item>
      </a-form>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import {
  PlusOutlined, EditOutlined, DeleteOutlined, EllipsisOutlined,
  CodeOutlined, DashboardOutlined, GlobalOutlined, CloudOutlined,
  ClockCircleOutlined, SettingOutlined, DatabaseOutlined, LockOutlined,
  ReloadOutlined, DesktopOutlined, DatabaseFilled, FolderOutlined,
  ExclamationCircleOutlined,
} from '@ant-design/icons-vue'
import { message, Modal } from 'ant-design-vue'
import dayjs from 'dayjs'
import { pageAppResource, addAppResource, updateAppResource, removeAppResource, testConnection, testSshConnection, getServerStatus, type ServerStatus } from '@/api/app/appResource'
import { getMyAccessibleApps } from '@/api/app/appProduct'
import type { AppResource } from '@/api/app/appResource/model'
import { enrichResourcesWithPermission } from '@/composables/useResourceAccess'
import { useAppPermission } from '@/composables/useAppPermission'
import PermissionGuard from '@/components/developer/PermissionGuard.vue'

definePageMeta({ layout: 'developer' })
useHead({ title: '服务器管理 - 开发者中心' })

const IPV4_REGEX = /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$/

function isValidIpAddress(value: string) {
  const input = value.trim()
  if (!input) return false
  if (IPV4_REGEX.test(input)) return true
  try { new URL(`http://[${input}]`); return true } catch { return false }
}

const loading = ref(false)
const saveLoading = ref(false)
const showAdd = ref(false)
const testingConnection = ref(false)
const testingPgConnection = ref(false)
const testingSsh = ref(false)
const searchText = ref('')
const editRecord = ref<AppResource | null>(null)
const formRef = ref()

// 服务器状态管理
const serverStatusMap = ref<Record<number, ServerStatus>>({})
const statusLoading = ref<Record<number, boolean>>({})
const statusErrorMap = ref<Record<number, string>>({})
let statusRefreshTimer: ReturnType<typeof setInterval> | null = null

const form = reactive({
  name: '',
  ip: '',
  sshPort: 22 as number | undefined,
  sshUsername: '',
  sshPassword: '',
  mysqlPort: 3306 as number | undefined,
  pgPort: 5432 as number | undefined,
  panelPort: undefined as number | undefined,
  panelUsername: '',
  panelPassword: '',
  panelPath: '',
  adminUsername: '',
  adminPassword: '',
  provider: undefined as string | undefined,
  appId: undefined as number | undefined,
  expireAt: null as any,
  remark: '',
})

const rules = {
  name: [{ required: true, message: '请输入服务器名称' }],
  ip: [
    { required: true, message: '请输入 IP 地址' },
    {
      validator: async (_rule: any, value: string) => {
        if (!value || !value.trim()) return Promise.resolve()
        if (isValidIpAddress(value)) return Promise.resolve()
        return Promise.reject(new Error('请输入合法的 IP 地址'))
      },
      trigger: ['blur', 'change'],
    },
  ],
}

const statusLabel: Record<string, string> = {
  running: '运行中',
  stopped: '已停止',
  expired: '已过期',
  pending: '配置中',
}

const providerLabel: Record<string, string> = {
  tencent: '腾讯云',
  aliyun: '阿里云',
  huawei: '华为云',
  other: '其他',
}

const list = ref<AppResource[]>([])
const appOptions = ref<any[]>([])
const { getAppPermission, accessibleAppIds } = useAppPermission()
const selectedAppId = ref<number | undefined>(undefined)

// 判断是否即将到期（30天内）
function isExpiringSoon(dateStr: string) {
  if (!dateStr) return false
  return dayjs(dateStr).diff(dayjs(), 'day') <= 30
}

// 复制文本到剪贴板
async function copyText(text: string) {
  try {
    await navigator.clipboard.writeText(text)
    message.success('已复制: ' + text)
  } catch {
    message.error('复制失败')
  }
}

// 打开 1Panel 面板
function open1Panel(item: AppResource) {
  const port = item.panelPort || 8888
  const path = item.panelPath || ''
  const url = `http://${item.ip}:${port}${path}`
  window.open(url, '_blank')
}

// 打开 SSH 链接
function openSsh(item: AppResource) {
  const port = item.sshPort || 22
  const user = item.sshUsername || 'root'
  const sshUrl = `ssh://${user}@${item.ip}:${port}`
  window.open(sshUrl, '_blank')
}

// 菜单操作
function handleMenuAction(key: string, item: AppResource) {
  if (key === 'edit') handleEdit(item)
  else if (key === 'ssh') openSsh(item)
  else if (key === 'panel') open1Panel(item)
  else if (key === 'delete') {
    Modal.confirm({
      title: '确定要移除此服务器？',
      content: `将移除「${item.name}」(${item.ip})`,
      okText: '确定移除',
      okType: 'danger',
      cancelText: '取消',
      onOk: () => handleDelete(item.resourceId!),
    })
  }
}

// 加载可访问的应用下拉列表（按权限过滤）
async function loadAppOptions() {
  try {
    appOptions.value = await getMyAccessibleApps()
  }
  catch {
    appOptions.value = []
  }
}

async function loadList() {
  loading.value = true
  try {
    const result = await pageAppResource({
      resourceType: 'server',
      keywords: searchText.value || undefined,
      appId: selectedAppId.value,
      page: 1,
      limit: 200,
    })
    list.value = enrichResourcesWithPermission(result?.list ?? [])

    // 加载完成后，自动获取有1Panel配置的服务器状态
    autoFetchServerStatus()
  } catch (e: any) {
    message.error(e.message || '加载失败')
  } finally {
    loading.value = false
  }
}

// 自动获取所有有1Panel配置的服务器状态（developer 及以上角色可查看）
async function autoFetchServerStatus() {
  const serversWithPanel = list.value.filter(s => (s.accessLevel ?? 1) >= 2 && s.panelPort)
  for (const server of serversWithPanel) {
    if (serverStatusMap.value[server.resourceId!]) {
      // 已有状态的服务器，30秒自动刷新
    } else {
      // 没有状态的服务器，获取一次
      await fetchServerStatus(server)
    }
  }
}

// 获取单个服务器状态
async function fetchServerStatus(item: AppResource) {
  if (!item.resourceId || !item.panelPort) return
  statusLoading.value[item.resourceId] = true
  delete statusErrorMap.value[item.resourceId]
  try {
    const status = await getServerStatus(item.resourceId)
    serverStatusMap.value[item.resourceId] = status
  } catch (e: any) {
    statusErrorMap.value[item.resourceId] = e.message || '获取状态失败'
  } finally {
    statusLoading.value[item.resourceId] = false
  }
}

// 手动刷新单个服务器状态
async function refreshStatus(item: AppResource) {
  await fetchServerStatus(item)
}

// 清理状态（资源删除时）
function clearServerStatus(resourceId: number) {
  delete serverStatusMap.value[resourceId]
  delete statusLoading.value[resourceId]
  delete statusErrorMap.value[resourceId]
}

function handleEdit(record: AppResource) {
  if (!record.isOwner) {
    message.warning('只有资源创建者才能编辑')
    return
  }
  editRecord.value = record
  Object.assign(form, {
    name: record.name,
    ip: record.ip,
    sshPort: record.sshPort || 22,
    sshUsername: record.sshUsername || '',
    sshPassword: record.sshPassword || '',
    mysqlPort: record.mysqlPort || 3306,
    pgPort: record.pgPort || 5432,
    panelPort: record.panelPort || undefined,
    panelUsername: record.panelUsername || '',
    panelPassword: record.panelPassword || '',
    panelPath: record.panelPath || '',
    adminUsername: record.adminUsername || '',
    adminPassword: record.adminPassword || '',
    provider: record.provider,
    appId: record.appId ? Number(record.appId) : undefined,
    expireAt: record.expireAt || null,
    remark: record.remark,
    resourceId: record.resourceId,
  })
  showAdd.value = true
}

async function handleDelete(resourceId: number) {
  const item = list.value.find(r => r.resourceId === resourceId)
  if (item && !item.isOwner) {
    message.warning('只有资源创建者才能删除')
    return
  }
  try {
    await removeAppResource(resourceId)
    message.success('已移除')
    clearServerStatus(resourceId)  // 清理状态缓存
    loadList()
  } catch (e: any) {
    message.error(e.message || '删除失败')
  }
}

async function handleSave() {
  await formRef.value?.validate()
  saveLoading.value = true
  try {
    const payload: AppResource = {
      resourceType: 'server',
      name: form.name,
      ip: form.ip.trim(),
      sshPort: form.sshPort || 22,
      sshUsername: form.sshUsername || undefined,
      sshPassword: form.sshPassword || undefined,
      mysqlPort: form.mysqlPort || 3306,
      pgPort: form.pgPort || 5432,
      panelPort: form.panelPort || undefined,
      panelUsername: form.panelUsername || undefined,
      panelPassword: form.panelPassword || undefined,
      panelPath: form.panelPath || undefined,
      adminUsername: form.adminUsername || undefined,
      adminPassword: form.adminPassword || undefined,
      provider: form.provider,
      appId: form.appId ? Number(form.appId) : undefined,
      expireAt: form.expireAt ? dayjs(form.expireAt).format('YYYY-MM-DD') : undefined,
      remark: form.remark,
    }
    if (editRecord.value) {
      payload.resourceId = editRecord.value.resourceId
      await updateAppResource(payload)
      message.success('保存成功')
    } else {
      await addAppResource(payload)
      message.success('添加成功')
    }
    showAdd.value = false
    resetForm()
    loadList()
  } catch (e: any) {
    message.error(e.message || '操作失败')
  } finally {
    saveLoading.value = false
  }
}

async function handleTestConnection() {
  if (!form.ip) { message.warning('请先填写 IP 地址'); return }
  testingConnection.value = true
  try {
    const result = await testConnection({
      host: form.ip.trim(),
      port: form.mysqlPort || 3306,
      dbType: 'MySQL',
      username: form.adminUsername,
      password: form.adminPassword,
    })
    message[result.success ? 'success' : 'error'](result.detail || result.message)
  } catch (e: any) {
    message.error(e.message || '连接测试失败')
  } finally {
    testingConnection.value = false
  }
}

async function handleTestPgConnection() {
  if (!form.ip) { message.warning('请先填写 IP 地址'); return }
  testingPgConnection.value = true
  try {
    const result = await testConnection({
      host: form.ip.trim(),
      port: form.pgPort || 5432,
      dbType: 'PostgreSQL',
      username: form.adminUsername,
      password: form.adminPassword,
    })
    message[result.success ? 'success' : 'error'](result.detail || result.message)
  } catch (e: any) {
    message.error(e.message || '连接测试失败')
  } finally {
    testingPgConnection.value = false
  }
}

async function handleTestSsh() {
  if (!form.ip) { message.warning('请先填写 IP 地址'); return }
  if (!form.sshUsername || !form.sshPassword) { message.warning('请先填写 SSH 用户名和密码'); return }
  testingSsh.value = true
  try {
    const result = await testSshConnection({
      host: form.ip.trim(),
      port: form.sshPort || 22,
      username: form.sshUsername,
      password: form.sshPassword,
    })
    message[result.success ? 'success' : 'error'](result.detail || result.message)
  } catch (e: any) {
    message.error(e.message || 'SSH 连接测试失败')
  } finally {
    testingSsh.value = false
  }
}

function resetForm() {
  editRecord.value = null
  formRef.value?.resetFields()
  Object.assign(form, {
    name: '', ip: '', sshPort: 22, sshUsername: '', sshPassword: '',
    mysqlPort: 3306, pgPort: 5432, panelPort: undefined,
    panelUsername: '', panelPassword: '', panelPath: '',
    adminUsername: '', adminPassword: '', provider: undefined, appId: undefined,
    expireAt: null, remark: '',
  })
}

onMounted(() => {
  loadAppOptions()
  loadList()
  // 启动定时刷新（每30秒刷新一次已有状态的服务器，developer 及以上角色）
  statusRefreshTimer = setInterval(() => {
    const serversWithStatus = list.value.filter(s => (s.accessLevel ?? 1) >= 2 && s.panelPort && serverStatusMap.value[s.resourceId!])
    serversWithStatus.forEach(server => {
      fetchServerStatus(server)
    })
  }, 30000)
})

onUnmounted(() => {
  // 清理定时器
  if (statusRefreshTimer) {
    clearInterval(statusRefreshTimer)
    statusRefreshTimer = null
  }
})
</script>

<style scoped>
.dev-page {
  padding: 24px;
  max-width: 1200px;
  margin: 0 auto;
}

/* 工具栏 */
.page-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
}
.toolbar-left {
  display: flex;
  align-items: center;
  gap: 12px;
}
.page-title {
  margin: 0;
  font-size: 20px;
  font-weight: 600;
}
.toolbar-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* 加载和空状态 */
.card-loading,
.card-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 300px;
}

/* 服务器卡片网格 */
.server-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 16px;
}

/* 单个卡片 */
.server-card {
  background: #fff;
  border: 1px solid #f0f0f0;
  border-radius: 10px;
  padding: 16px 20px;
  transition: all 0.2s;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.server-card:hover {
  border-color: #91caff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.card-expired {
  opacity: 0.7;
}

/* 卡片头部 */
.card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}
.card-header-left {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.server-name {
  font-size: 16px;
  font-weight: 600;
  color: #1a1a1a;
}

/* 卡片信息区 */
.card-info {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: #666;
}
.info-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.info-label {
  color: #999;
  font-size: 14px;
  display: flex;
  align-items: center;
}
.info-value {
  color: #333;
}
.ip-value {
  font-family: 'SF Mono', 'Menlo', 'Monaco', 'Consolas', monospace;
  cursor: pointer;
  padding: 1px 6px;
  border-radius: 4px;
  transition: background 0.15s;
}
.ip-value:hover {
  background: #e6f4ff;
  color: #1677ff;
}
.info-extra {
  color: #999;
  font-size: 12px;
}
.text-danger {
  color: #ff4d4f;
}

/* 端口标签区 */
.card-ports {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.card-ports .ant-tag {
  margin: 0;
  font-size: 11px;
  font-family: 'SF Mono', 'Menlo', monospace;
}

/* 服务器状态区 */
.card-status {
  background: #fafafa;
  border-radius: 6px;
  padding: 10px 12px;
  font-size: 12px;
}
.status-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.status-title {
  font-weight: 500;
  color: #333;
}
.status-content {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.status-online {
  display: flex;
  align-items: center;
  gap: 6px;
  color: #52c41a;
}
.status-online.offline {
  color: #ff4d4f;
}
.status-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #52c41a;
}
.status-dot.offline {
  background: #ff4d4f;
}
.status-uptime {
  color: #999;
  font-size: 11px;
  margin-left: 4px;
}
.status-bars {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.status-bar-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.status-bar-label {
  display: flex;
  align-items: center;
  gap: 4px;
  color: #666;
  font-size: 11px;
}
.status-bar-value {
  margin-left: auto;
  font-weight: 500;
  color: #333;
}
.status-error {
  color: #ff4d4f;
  text-align: center;
  padding: 8px 0;
}
.status-empty {
  color: #999;
  text-align: center;
  padding: 8px 0;
}

/* 卡片操作区 */
.card-actions {
  display: flex;
  gap: 8px;
  padding-top: 4px;
  border-top: 1px solid #f5f5f5;
}

/* 权限提示 */
.access-hint {
  margin-top: 2px;
}
.access-hint-text {
  font-size: 11px;
  color: #faad14;
}

/* 表单分区标题 */
.form-section-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0 4px;
  font-size: 14px;
  font-weight: 500;
  color: #333;
  border-top: 1px solid #f0f0f0;
  margin-top: 12px;
}
.form-section-header:first-child {
  border-top: none;
  margin-top: 0;
}
.form-section-hint {
  font-size: 12px;
  font-weight: 400;
  color: #999;
}
</style>
