<template>
  <div class="dev-page">
    <div class="page-toolbar">
      <div class="toolbar-left">
        <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>
        <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 class="toolbar-right">
        <a-input-search
          v-model:value="searchText"
          placeholder="搜索数据库名称 / 地址"
          style="width: 240px"
          @search="loadList"
        />
      </div>
    </div>

    <div class="notice-bar">
      <InfoCircleOutlined class="notice-icon" />
      <span>在此统一管理应用使用的数据库实例。选择服务器后，添加数据库将自动在远程服务器上创建。</span>
    </div>

    <a-table
      :columns="columns"
      :data-source="list"
      :loading="loading"
      :pagination="pagination"
      row-key="resourceId"
      @change="handleTableChange"
    >
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'dbType'">
          <a-tag :color="typeColor[record.dbType]">{{ record.dbType }}</a-tag>
        </template>
        <template v-if="column.key === 'port'">
          {{ record.port || '-' }}
        </template>
        <template v-if="column.key === 'status'">
          <a-badge
            :status="statusBadge[record.status] || 'default'"
            :text="statusLabel[record.status] || record.status"
          />
        </template>
        <template v-if="column.key === 'action'">
          <a-space>
            <a-button
              v-if="record.status === 'failed' && (record.isOwner || getAppPermission(record.appId)?.canEditResource)"
              type="link"
              size="small"
              :loading="retryingId === record.resourceId"
              @click="handleRetry(record)"
            >
              重试
            </a-button>
            <a-popconfirm
              v-if="record.isOwner || getAppPermission(record.appId)?.canEditResource"
              title="确定要重置密码吗？"
              ok-text="确定"
              cancel-text="取消"
              @confirm="handleResetPassword(record)"
            >
              <a-button type="link" size="small" :loading="resettingId === record.resourceId">
                <template #icon><SyncOutlined /></template>
                重置密码
              </a-button>
            </a-popconfirm>
            <a-divider v-if="record.isOwner || getAppPermission(record.appId)?.canEditResource" type="vertical" />
            <a-popconfirm v-if="record.isOwner || getAppPermission(record.appId)?.canEditResource" title="确定要移除此数据库？" @confirm="handleDelete(record)">
              <a-button type="link" size="small" danger>移除</a-button>
            </a-popconfirm>
            <!-- 无权限：只读状态 -->
            <span v-if="!record.isOwner && !getAppPermission(record.appId)?.canEditResource" style="font-size: 12px; color: #faad14;">
              <LockOutlined /> 只读
            </span>
          </a-space>
        </template>
      </template>
    </a-table>

    <a-modal
      v-model:open="showAdd"
      title="添加数据库"
      ok-text="保存"
      cancel-text="取消"
      :confirm-loading="saveLoading"
      width="560px"
      @ok="handleSave"
      @cancel="resetForm"
    >
      <a-form ref="formRef" :model="form" :rules="rules" layout="vertical" style="margin-top: 8px">
        <!-- 所属服务器 -->
        <a-form-item label="所属服务器" name="serverResourceId">
          <a-select
            v-model:value="form.serverResourceId"
            placeholder="选择服务器（用于远程建库）"
            allow-clear
            show-search
            :filter-option="filterServerOption"
            @change="handleServerChange"
          >
            <a-select-option v-for="s in serverOptions" :key="s.resourceId" :value="s.resourceId">
              {{ s.name }}（{{ s.ip }} / MySQL:{{ s.mysqlPort || 3306 }} / PG:{{ s.pgPort || 5432 }}）
            </a-select-option>
          </a-select>
          <div v-if="form.serverResourceId" class="form-tip">
            <ApiOutlined /> 将在所选服务器上自动创建数据库
          </div>
          <div v-else class="form-tip form-tip-warn">
            不选择服务器则仅记录信息，不会远程创建数据库
          </div>
        </a-form-item>

        <a-form-item label="数据库名称" name="name">
          <a-input v-model:value="form.name" placeholder="如：db_shop" />
        </a-form-item>
        <a-form-item label="数据库类型" name="dbType">
          <a-select v-model:value="form.dbType" placeholder="请选择类型">
            <a-select-option value="MySQL">MySQL</a-select-option>
            <a-select-option value="PostgreSQL">PostgreSQL</a-select-option>
            <a-select-option value="Redis">Redis</a-select-option>
            <a-select-option value="MongoDB">MongoDB</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="连接地址" name="host">
          <a-input v-model:value="form.host" placeholder="Host / IP 地址（选择服务器后自动填充）" :disabled="!!form.serverResourceId" />
        </a-form-item>
        <a-form-item label="端口" name="port">
          <a-input-number v-model:value="form.port" :min="1" :max="65535" :precision="0" style="width: 100%" placeholder="如：3306" :disabled="!!form.serverResourceId" />
        </a-form-item>
        <a-form-item label="用户名" name="dbUsername">
          <a-input v-model:value="form.dbUsername" placeholder="数据库用户名（选择服务器后将自动创建）" />
        </a-form-item>
        <a-form-item label="密码" name="dbPassword">
          <a-input-password v-model:value="form.dbPassword" placeholder="数据库密码">
            <template #addonAfter>
              <a-button type="link" size="small" style="padding: 0; height: auto;" @click="refreshPassword">
                <template #icon><SyncOutlined /></template>
                刷新
              </a-button>
            </template>
          </a-input-password>
        </a-form-item>
        <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-form-item label="备注" name="remark">
          <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, InfoCircleOutlined, SyncOutlined, ApiOutlined, LockOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import { pageAppResource, addAppResource, removeAppResource, retryCreateDatabase, resetDatabasePassword } from '@/api/app/appResource'
import { getMyAccessibleApps } from '@/api/app/appProduct'
import { useAppPermission } from '@/composables/useAppPermission'
import PermissionGuard from '@/components/developer/PermissionGuard.vue'
import type { AppResource } from '@/api/app/appResource/model'
import { enrichResourcesWithPermission } from '@/composables/useResourceAccess'

definePageMeta({ layout: 'developer' })
useHead({ title: '数据库管理 - 开发者中心' })

const loading = ref(false)
const saveLoading = ref(false)
const resettingId = ref<number | null>(null)
const showAdd = ref(false)
const searchText = ref('')
const retryingId = ref<number | null>(null)
const formRef = ref()
const selectedAppId = ref<number | undefined>(undefined)
const { getAppPermission } = useAppPermission()

const form = reactive({
  name: '',
  dbType: undefined as string | undefined,
  serverResourceId: undefined as number | undefined,
  host: '',
  port: undefined as number | undefined,
  dbUsername: '',
  dbPassword: '',
  appId: undefined as number | undefined,
  remark: '',
})

// 生成随机密码（12位，包含大小写字母、数字、特殊字符）
function generateRandomPassword(): string {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*'
  let password = ''
  for (let i = 0; i < 12; i++) {
    password += chars.charAt(Math.floor(Math.random() * chars.length))
  }
  return password
}

// 监听数据库名称变化，自动填充用户名和密码
watch(() => form.name, (newName) => {
  if (newName) {
    form.dbUsername = newName
    if (!form.dbPassword) {
      form.dbPassword = generateRandomPassword()
    }
  }
})

// 监听数据库类型变化，如果已选服务器则自动刷新端口
watch(() => form.dbType, () => {
  if (form.serverResourceId) {
    handleServerChange(form.serverResourceId)
  }
})

// 校验连接地址
function validateHost(_rule: any, value: string) {
  if (!value) return Promise.reject('请输入连接地址')
  if (/[a-zA-Z\-]/.test(value)) return Promise.resolve()
  const ipv4Reg = /^(25[0-5]|2[0-4]\d|1\d{1,2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d{1,2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d{1,2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d{1,2}|[1-9]?\d)$/
  if (ipv4Reg.test(value)) return Promise.resolve()
  if (/^[\d.]+$/.test(value) && value.includes('.'))
    return Promise.reject('IPv4 地址格式不正确（如：192.168.1.1）')
  if (value.includes(':')) {
    const ipv6Reg = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^(([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?::(([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?$/
    if (ipv6Reg.test(value)) return Promise.resolve()
    return Promise.reject('IPv6 地址格式不正确')
  }
  return Promise.resolve()
}

// 校验端口号
function validatePort(_rule: any, value: number) {
  if (value === undefined || value === null || value === '') return Promise.resolve()
  const num = Number(value)
  if (isNaN(num) || !Number.isInteger(num) || num < 1 || num > 65535) {
    return Promise.reject('端口号须为 1 ~ 65535 之间的整数')
  }
  return Promise.resolve()
}

// 校验数据库名称
function validateDbName(_rule: any, value: string) {
  if (!value) return Promise.reject('请输入数据库名称')
  const dbNameReg = /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/
  if (!dbNameReg.test(value)) {
    return Promise.reject('命名格式：db_shop（小写字母开头，下划线分隔，仅含小写字母、数字、下划线）')
  }
  return Promise.resolve()
}

const rules = {
  name: [
    { required: true, message: '请输入数据库名称' },
    { validator: validateDbName, trigger: 'blur' },
  ],
  dbType: [{ required: true, message: '请选择数据库类型' }],
  host: [
    { required: true, message: '请输入连接地址' },
    { validator: validateHost, trigger: 'blur' },
  ],
  port: [{ validator: validatePort, trigger: 'blur' }],
}

const statusLabel: Record<string, string> = {
  running: '运行中',
  pending: '创建中',
  failed: '创建失败',
  stopped: '已停止',
  expired: '已过期',
}

const statusBadge: Record<string, string> = {
  running: 'success',
  pending: 'processing',
  failed: 'error',
  stopped: 'default',
  expired: 'warning',
}

const typeColor: Record<string, string> = {
  MySQL: 'blue',
  PostgreSQL: 'purple',
  Redis: 'red',
  MongoDB: 'green',
}

const columns = [
  { title: '数据库名称', dataIndex: 'name', key: 'name' },
  { title: '类型', dataIndex: 'dbType', key: 'dbType' },
  { title: '连接地址', dataIndex: 'host', key: 'host' },
  { title: '端口', dataIndex: 'port', key: 'port' },
  { title: '用户名', dataIndex: 'dbUsername', key: 'dbUsername', customRender: ({ record }: any) => {
    if ((record.accessLevel ?? 1) >= 2) return record.dbUsername || '-'
    return '***'
  } },
  // { title: '关联应用', dataIndex: 'productName', key: 'productName' },
  { title: '状态', dataIndex: 'status', key: 'status' },
  { title: '操作', key: 'action', width: 180 },
]

const pagination = reactive({ current: 1, pageSize: 10, total: 0 })
const list = ref<AppResource[]>([])
const appOptions = ref<any[]>([])
const serverOptions = ref<any[]>([])

// 服务器搜索过滤
function filterServerOption(input: string, option: any) {
  const label = option.children?.[0]?.children?.toString() || ''
  return label.toLowerCase().includes(input.toLowerCase())
}

// 选择服务器后自动填充 host/port
function handleServerChange(serverResourceId: number | undefined) {
  if (serverResourceId) {
    const server = serverOptions.value.find((s: any) => s.resourceId === serverResourceId)
    if (server) {
      form.host = server.ip
      // 根据数据库类型填充对应端口
      if (form.dbType === 'PostgreSQL') {
        form.port = server.pgPort || 5432
      } else {
        form.port = server.mysqlPort || 3306
      }
    }
  }
}

// 加载应用下拉列表（仅当前用户可访问的应用）
async function loadAppOptions() {
  try {
    appOptions.value = await getMyAccessibleApps()
  }
  catch {
    appOptions.value = []
  }
}

// 加载服务器下拉列表（只加载有管理员凭据的服务器）
async function loadServerOptions() {
  try {
    const res = await pageAppResource({ resourceType: 'server', page: 1, limit: 200 })
    const servers = res?.list ?? []
    // 只展示配置了管理员用户名的服务器
    serverOptions.value = servers.filter((s: any) => s.adminUsername)
  }
  catch {
    serverOptions.value = []
  }
}

async function loadList() {
  loading.value = true
  try {
    const result = await pageAppResource({
      resourceType: 'database',
      keywords: searchText.value || undefined,
      appId: selectedAppId.value,
      page: pagination.current,
      limit: pagination.pageSize,
    })
    list.value = enrichResourcesWithPermission(result?.list ?? [])
    pagination.total = result?.count ?? 0
  }
  catch (e: any) {
    message.error(e.message || '加载失败')
  }
  finally {
    loading.value = false
  }
}

function handleTableChange(pag: any) {
  pagination.current = pag.current
  loadList()
}

async function handleDelete(record: AppResource) {
  try {
    if (record.serverResourceId && (record.dbType === 'MySQL' || record.dbType === 'PostgreSQL')) {
      message.loading({ content: '正在删除远程数据库...', key: 'deleteDb' })
    }
    await removeAppResource(record.resourceId!)
    message.success({ content: '已移除', key: 'deleteDb' })
    loadList()
  }
  catch (e: any) {
    message.error({ content: e.message || '删除失败', key: 'deleteDb' })
  }
}

async function handleRetry(record: AppResource) {
  if (!record.resourceId) return
  retryingId.value = record.resourceId
  try {
    await retryCreateDatabase(record.resourceId)
    message.success('已开始重新创建，请稍后刷新查看状态')
    // 3秒后自动刷新
    setTimeout(loadList, 3000)
  }
  catch (e: any) {
    message.error(e.message || '重试失败')
  }
  finally {
    retryingId.value = null
  }
}

// 重置密码
async function handleResetPassword(record: AppResource) {
  if (!record.resourceId) return
  resettingId.value = record.resourceId
  try {
    const result = await resetDatabasePassword(record.resourceId)
    message.success(`密码已重置为：${result.password}（请妥善保管）`)
    loadList()
  }
  catch (e: any) {
    message.error(e.message || '重置失败')
  }
  finally {
    resettingId.value = null
  }
}

async function handleSave() {
  await formRef.value?.validate()
  saveLoading.value = true
  try {
    const payload: AppResource = {
      resourceType: 'database',
      name: form.name,
      dbType: form.dbType,
      serverResourceId: form.serverResourceId ? Number(form.serverResourceId) : undefined,
      host: form.host || undefined,
      port: form.port,
      dbUsername: form.dbUsername || undefined,
      dbPassword: form.dbPassword || undefined,
      appId: form.appId ? Number(form.appId) : undefined,
      remark: form.remark,
    }
    await addAppResource(payload)
    if (form.serverResourceId && (form.dbType === 'MySQL' || form.dbType === 'PostgreSQL')) {
      message.success('添加成功，正在远程创建数据库...')
      // 3秒后刷新状态
      setTimeout(loadList, 3000)
    }
    else {
      message.success('添加成功')
    }
    showAdd.value = false
    resetForm()
    loadList()
  }
  catch (e: any) {
    message.error(e.message || '操作失败')
  }
  finally {
    saveLoading.value = false
  }
}

function resetForm() {
  formRef.value?.resetFields()
  Object.assign(form, { name: '', dbType: undefined, serverResourceId: undefined, host: '', port: undefined, dbUsername: '', dbPassword: '', appId: undefined, remark: '' })
}

// 刷新密码
function refreshPassword() {
  form.dbPassword = generateRandomPassword()
}

onMounted(() => {
  loadAppOptions()
  loadServerOptions()
  loadList()
})
</script>

<style scoped>
.dev-page { padding: 24px; max-width: 1100px; }
.page-toolbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.toolbar-left { display: flex; align-items: center; gap: 12px; }
.toolbar-right { display: flex; gap: 8px; }
.notice-bar {
  display: flex; align-items: center; gap: 8px;
  background: #e6f4ff; border: 1px solid #91caff;
  border-radius: 6px; padding: 8px 14px; margin-bottom: 16px;
  font-size: 13px; color: #1677ff;
}
.notice-icon { font-size: 15px; }
.form-tip {
  font-size: 12px; color: #52c41a; margin-top: 4px;
  display: flex; align-items: center; gap: 4px;
}
.form-tip-warn { color: #faad14; }
</style>
