<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-select v-model:value="filterIcp" placeholder="备案状态" style="width: 120px" allow-clear @change="loadList">
          <a-select-option :value="true">已备案</a-select-option>
          <a-select-option :value="false">未备案</a-select-option>
        </a-select>
        <a-select v-model:value="filterSsl" placeholder="SSL 状态" style="width: 120px" allow-clear @change="loadList">
          <a-select-option :value="true">已绑定</a-select-option>
          <a-select-option :value="false">未绑定</a-select-option>
        </a-select>
        <a-input-search v-model:value="searchText" placeholder="搜索域名 / 备案号" 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 class="notice-bar">
      <InfoCircleOutlined class="notice-icon" />
      <span>在此管理应用所使用的域名，支持关联 SSL 证书和绑定具体应用。</span>
    </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="暂无域名，点击右上角添加">
        <a-button type="primary" @click="showAdd = true"><template #icon><PlusOutlined /></template>添加域名</a-button>
      </a-empty>
    </div>
    <div v-else class="domain-grid">
      <div v-for="item in list" :key="item.resourceId" class="domain-card" :class="{ 'card-expiring': isNearExpiry(item.expireAt) }">
        <!-- 卡片头部 -->
        <div class="card-header">
          <div class="card-header-left">
            <div class="domain-name" @click="copyText(item.domain!)">
              <GlobalOutlined />
              <span class="domain-text">{{ item.domain }}</span>
              <CopyOutlined class="copy-icon" />
            </div>
            <div class="domain-tags">
              <a-tag :color="item.icp ? 'green' : 'orange'" size="small">{{ item.icp ? '已备案' : '未备案' }}</a-tag>
              <a-tag :color="item.sslBound ? 'blue' : 'default'" size="small">{{ item.sslBound ? 'SSL 已绑定' : 'SSL 未绑定' }}</a-tag>
              <a-tag v-if="isNearExpiry(item.expireAt)" color="red" size="small">即将到期</a-tag>
            </div>
          </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.sslBound" key="bindSsl"><template #icon><SafetyOutlined /></template>绑定 SSL</a-menu-item>
                <a-menu-item v-if="item.sslBound" key="unbindSsl"><template #icon><DisconnectOutlined /></template>解绑 SSL</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">注册商</span><span class="info-value">{{ item.registrar || '-' }}</span></div>
          <div class="info-row">
            <span class="info-label">备案号</span>
            <span class="info-value icp-value" @click="item.icpNo && copyText(item.icpNo)">
              {{ item.icpNo || '未备案' }}<CopyOutlined v-if="item.icpNo" class="copy-icon-small" />
            </span>
          </div>
          <div class="info-row">
            <span class="info-label">SSL 证书</span>
            <span class="info-value">
              <template v-if="item.sslBound && item.sslCertName"><SafetyOutlined style="color: #52c41a; margin-right: 4px;" />{{ item.sslCertName }}</template>
              <span v-else class="text-muted">未绑定</span>
            </span>
          </div>
          <div class="info-row"><span class="info-label">关联应用</span><span class="info-value">{{ item.appName || '未关联' }}</span></div>
          <div class="info-row">
            <span class="info-label">到期时间</span>
            <span class="info-value" :class="{ 'text-warning': isNearExpiry(item.expireAt), 'text-danger': isExpired(item.expireAt) }">{{ item.expireAt || '-' }}</span>
          </div>
        </div>

        <!-- 快捷操作区 -->
        <div class="card-actions">
          <a-button v-if="item.isOwner || getAppPermission(item.appId)?.canEditResource" size="small" @click="handleEdit(item)"><template #icon><EditOutlined /></template>编辑</a-button>
          <a-button v-if="!item.sslBound" size="small" @click="handleBindSsl(item)"><template #icon><SafetyOutlined /></template>绑定 SSL</a-button>
          <a-button v-if="item.sslBound" size="small" @click="handleViewSsl(item)"><template #icon><EyeOutlined /></template>查看证书</a-button>
          <span v-if="!item.isOwner && !getAppPermission(item.appId)?.canEditResource" style="font-size: 11px; color: #faad14; display:flex; align-items:center; gap:4px;">
            <LockOutlined /> 协作者
          </span>
        </div>
      </div>
    </div>

    <!-- 分页 -->
    <div v-if="list.length > 0" class="pagination-wrapper">
      <a-pagination v-model:current="pagination.current" v-model:page-size="pagination.pageSize" :total="pagination.total" :page-size-options="['12', '24', '48']" show-size-changer show-total @change="handlePageChange" />
    </div>

    <!-- 添加/编辑弹窗 -->
    <a-modal v-model:open="showAdd" :title="editRecord ? '编辑域名' : '添加域名'" 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">
        <div class="form-section-header"><GlobalOutlined /><span>基本信息</span></div>
        <a-row :gutter="16">
          <a-col :span="16">
            <a-form-item label="域名" name="domain">
              <a-input v-model:value="form.domain" placeholder="如：example.com" :disabled="!!editRecord" @blur="handleDomainBlur" />
            </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>
        <a-row :gutter="16">
          <a-col :span="12">
            <a-form-item label="注册商" name="registrar">
              <a-input v-model:value="form.registrar" placeholder="如：腾讯云、阿里云" />
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <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-row>

        <div class="form-section-header"><SafetyCertificateOutlined /><span>ICP 备案</span></div>
        <a-row :gutter="16">
          <a-col :span="8">
            <a-form-item label="备案状态" name="icp">
              <a-radio-group v-model:value="form.icp">
                <a-radio :value="true">已备案</a-radio>
                <a-radio :value="false">未备案</a-radio>
              </a-radio-group>
            </a-form-item>
          </a-col>
          <a-col :span="16">
            <a-form-item label="ICP 备案号" name="icpNo">
              <a-input v-model:value="form.icpNo" placeholder="如：粤ICP备XXXXXXXX号" />
            </a-form-item>
          </a-col>
        </a-row>

        <div class="form-section-header"><SafetyOutlined /><span>SSL 证书</span><span class="form-section-hint">可选，绑定已有证书</span></div>
        <a-form-item label="选择证书" name="sslResourceId">
          <a-select v-model:value="form.sslResourceId" placeholder="选择要绑定的 SSL 证书" allow-clear @change="handleSslChange">
            <a-select-option v-for="cert in sslOptions" :key="cert.resourceId" :value="cert.resourceId">
              <div style="display: flex; align-items: center; gap: 8px;">
                <span>{{ cert.name }}</span>
                <a-tag size="small" :color="certTypeColor[cert.certType!]">{{ cert.certType }}</a-tag>
                <span style="color: #999; font-size: 12px;">{{ cert.domain }}</span>
              </div>
            </a-select-option>
          </a-select>
        </a-form-item>

        <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>

    <!-- 绑定 SSL 弹窗 -->
    <a-modal v-model:open="showBindSsl" title="绑定 SSL 证书" ok-text="绑定" cancel-text="取消" @ok="confirmBindSsl" @cancel="cancelBindSsl">
      <a-form layout="vertical">
        <a-form-item label="域名"><a-input :value="currentDomain?.domain" disabled /></a-form-item>
        <a-form-item label="选择 SSL 证书">
          <a-select v-model:value="bindSslForm.sslResourceId" placeholder="选择要绑定的 SSL 证书">
            <a-select-option v-for="cert in sslOptions" :key="cert.resourceId" :value="cert.resourceId">
              <div style="display: flex; align-items: center; gap: 8px;">
                <span>{{ cert.name }}</span>
                <a-tag size="small" :color="certTypeColor[cert.certType!]">{{ cert.certType }}</a-tag>
                <span style="color: #999; font-size: 12px;">{{ cert.domain }}</span>
              </div>
            </a-select-option>
          </a-select>
        </a-form-item>
      </a-form>
    </a-modal>

    <!-- 查看 SSL 证书弹窗 -->
    <a-modal v-model:open="showViewSsl" title="SSL 证书信息" :footer="null" @cancel="showViewSsl = false">
      <div v-if="currentSslCert" class="ssl-info">
        <div class="ssl-info-item"><span class="ssl-info-label">证书名称</span><span class="ssl-info-value">{{ currentSslCert.name }}</span></div>
        <div class="ssl-info-item"><span class="ssl-info-label">绑定域名</span><span class="ssl-info-value">{{ currentSslCert.domain }}</span></div>
        <div class="ssl-info-item"><span class="ssl-info-label">证书类型</span><span class="ssl-info-value"><a-tag :color="certTypeColor[currentSslCert.certType!]">{{ currentSslCert.certType }}</a-tag></span></div>
        <div class="ssl-info-item"><span class="ssl-info-label">颁发机构</span><span class="ssl-info-value">{{ currentSslCert.issuer || '-' }}</span></div>
        <div class="ssl-info-item"><span class="ssl-info-label">到期时间</span><span class="ssl-info-value" :class="{ 'text-warning': isNearExpiry(currentSslCert.expireAt) }">{{ currentSslCert.expireAt }}</span></div>
        <div class="ssl-info-item"><span class="ssl-info-label">加密算法</span><span class="ssl-info-value">{{ currentSslCert.algorithm || '-' }} {{ currentSslCert.keyBits ? `(${currentSslCert.keyBits}位)` : '' }}</span></div>
      </div>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined, EditOutlined, DeleteOutlined, EllipsisOutlined, GlobalOutlined, CopyOutlined, InfoCircleOutlined, SafetyOutlined, SafetyCertificateOutlined, DisconnectOutlined, EyeOutlined, LockOutlined } from '@ant-design/icons-vue'
import { message, Modal } from 'ant-design-vue'
import dayjs from 'dayjs'
import { pageAppResource, addAppResource, updateAppResource, removeAppResource } 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, AppResourceParam } from '@/api/app/appResource/model'
import { enrichResourcesWithPermission } from '@/composables/useResourceAccess'

definePageMeta({ layout: 'developer' })
useHead({ title: '域名管理 - 开发者中心' })

const DOMAIN_REGEX = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/

const loading = ref(false)
const saveLoading = ref(false)
const showAdd = ref(false)
const showBindSsl = ref(false)
const showViewSsl = ref(false)
const searchText = ref('')
const filterIcp = ref<boolean | undefined>(undefined)
const filterSsl = ref<boolean | undefined>(undefined)
const editRecord = ref<AppResource | null>(null)
const currentDomain = ref<AppResource | null>(null)
const currentSslCert = ref<AppResource | null>(null)
const formRef = ref()
const selectedAppId = ref<number | undefined>(undefined)
const { getAppPermission } = useAppPermission()

const form = reactive({ domain: '', registrar: '', icp: false, icpNo: '', sslResourceId: undefined as number | undefined, appId: undefined as number | undefined, expireAt: null as any, remark: '' })
const bindSslForm = reactive({ sslResourceId: undefined as number | undefined })

const rules = {
  domain: [
    { required: true, message: '请输入域名' },
    { validator: async (_rule: any, value: string) => { if (!value) return Promise.resolve(); const domain = value.trim().toLowerCase(); const testDomain = domain.startsWith('*.') ? domain.slice(2) : domain; if (DOMAIN_REGEX.test(testDomain)) return Promise.resolve(); return Promise.reject(new Error('请输入合法的域名')) }, trigger: ['blur', 'change'] },
  ],
}

const certTypeColor: Record<string, string> = { DV: 'blue', OV: 'purple', EV: 'gold' }
const pagination = reactive({ current: 1, pageSize: 12, total: 0 })
const list = ref<AppResource[]>([])
const appOptions = ref<any[]>([])
const sslOptions = ref<AppResource[]>([])

function isNearExpiry(dateStr?: string): boolean { if (!dateStr) return false; return dayjs(dateStr).diff(dayjs(), 'day') <= 30 && dayjs(dateStr).diff(dayjs(), 'day') >= 0 }
function isExpired(dateStr?: string): boolean { if (!dateStr) return false; return dayjs(dateStr).diff(dayjs(), 'day') < 0 }

async function copyText(text: string) { try { await navigator.clipboard.writeText(text); message.success('已复制: ' + text) } catch { message.error('复制失败') } }
function handleDomainBlur() { if (form.domain && !form.icpNo) { } }
function handleSslChange(value: number) { if (value) form.icp = true }

function handleMenuAction(key: string, item: AppResource) {
  if (key === 'edit') handleEdit(item)
  else if (key === 'bindSsl') handleBindSsl(item)
  else if (key === 'unbindSsl') handleUnbindSsl(item)
  else if (key === 'delete') {
    if (!item.isOwner) { message.warning('只有域名创建者才能删除'); return }
    Modal.confirm({ title: '确定要移除此域名？', content: `将移除「${item.domain}」`, okText: '确定移除', okType: 'danger', cancelText: '取消', onOk: () => handleDelete(item.resourceId!) })
  }
}

async function loadAppOptions() { try { appOptions.value = await getMyAccessibleApps() } catch { appOptions.value = [] } }
async function loadSslOptions() { try { const result = await pageAppResource({ resourceType: 'ssl', page: 1, limit: 200 }); sslOptions.value = result?.list ?? [] } catch { sslOptions.value = [] } }

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

function handlePageChange(page: number, pageSize: number) { pagination.current = page; pagination.pageSize = pageSize; loadList() }

function handleEdit(record: AppResource) {
  if (!record.isOwner) {
    message.warning('只有域名创建者才能编辑')
    return
  }
  editRecord.value = record
  Object.assign(form, { domain: record.domain, registrar: record.registrar, icp: record.icp ?? false, icpNo: record.icpNo, sslResourceId: record.sslResourceId, 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) { try { await removeAppResource(resourceId); message.success('已移除'); loadList() } catch (e: any) { message.error(e.message || '删除失败') } }

async function handleSave() {
  await formRef.value?.validate()
  saveLoading.value = true
  try {
    const payload: AppResource = { resourceType: 'domain', name: form.domain, domain: form.domain.trim().toLowerCase(), registrar: form.registrar, icp: form.icp, icpNo: form.icpNo, sslResourceId: form.sslResourceId, sslBound: !!form.sslResourceId, 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 }
}

function handleBindSsl(item: AppResource) { currentDomain.value = item; bindSslForm.sslResourceId = undefined; showBindSsl.value = true }

async function confirmBindSsl() {
  if (!bindSslForm.sslResourceId || !currentDomain.value) { message.warning('请选择 SSL 证书'); return }
  try {
    const payload: AppResource = { resourceId: currentDomain.value.resourceId, resourceType: 'domain', domain: currentDomain.value.domain, sslResourceId: bindSslForm.sslResourceId, sslBound: true }
    await updateAppResource(payload)
    message.success('SSL 证书绑定成功')
    showBindSsl.value = false
    loadList()
  } catch (e: any) { message.error(e.message || '绑定失败') }
}

function cancelBindSsl() { showBindSsl.value = false; bindSslForm.sslResourceId = undefined; currentDomain.value = null }

async function handleUnbindSsl(item: AppResource) {
  Modal.confirm({ title: '确定要解绑 SSL 证书？', content: `域名「${item.domain}」将解除与证书「${item.sslCertName || '未知'}」的绑定`, okText: '确定解绑', okType: 'warning', cancelText: '取消', onOk: async () => { try { const payload: AppResource = { resourceId: item.resourceId, resourceType: 'domain', domain: item.domain, sslResourceId: undefined, sslBound: false }; await updateAppResource(payload); message.success('SSL 证书解绑成功'); loadList() } catch (e: any) { message.error(e.message || '解绑失败') } } })
}

async function handleViewSsl(item: AppResource) {
  if (!item.sslResourceId) { message.warning('未绑定 SSL 证书'); return }
  currentDomain.value = item
  const cert = sslOptions.value.find(c => c.resourceId === item.sslResourceId)
  if (cert) { currentSslCert.value = cert; showViewSsl.value = true }
  else { message.warning('证书信息加载失败') }
}

function resetForm() { editRecord.value = null; formRef.value?.resetFields(); Object.assign(form, { domain: '', registrar: '', icp: false, icpNo: '', sslResourceId: undefined, appId: undefined, expireAt: null, remark: '' }) }

onMounted(() => { loadAppOptions(); loadSslOptions(); loadList() })
</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; }
.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; }
.card-loading, .card-empty { display: flex; align-items: center; justify-content: center; min-height: 300px; }
.domain-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: 16px; }
.domain-card { background: #fff; border: 1px solid #f0f0f0; border-radius: 10px; padding: 16px 20px; transition: all 0.2s; display: flex; flex-direction: column; gap: 12px; }
.domain-card:hover { border-color: #91caff; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); }
.card-expiring { border-color: #ffa39e; background: #fff2f0; }
.card-header { display: flex; align-items: flex-start; justify-content: space-between; }
.card-header-left { display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 0; }
.domain-name { display: flex; align-items: center; gap: 8px; font-size: 16px; font-weight: 600; color: #1a1a1a; cursor: pointer; padding: 2px 6px; border-radius: 4px; transition: background 0.15s; }
.domain-name:hover { background: #e6f4ff; color: #1677ff; }
.domain-text { font-family: 'SF Mono', 'Menlo', 'Monaco', 'Consolas', monospace; }
.copy-icon { font-size: 12px; opacity: 0; transition: opacity 0.2s; color: #1677ff; }
.domain-name:hover .copy-icon { opacity: 1; }
.domain-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.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; width: 70px; flex-shrink: 0; }
.info-value { color: #333; flex: 1; }
.icp-value { cursor: pointer; padding: 1px 4px; border-radius: 4px; transition: background 0.15s; display: flex; align-items: center; gap: 4px; }
.icp-value:hover { background: #e6f4ff; color: #1677ff; }
.copy-icon-small { font-size: 10px; opacity: 0.6; }
.text-muted { color: #999; }
.text-warning { color: #fa8c16; font-weight: 500; }
.text-danger { color: #ff4d4f; font-weight: 500; }
.card-actions { display: flex; gap: 8px; padding-top: 4px; border-top: 1px solid #f5f5f5; }
.pagination-wrapper { display: flex; justify-content: flex-end; margin-top: 24px; padding-top: 16px; border-top: 1px solid #f0f0f0; }
.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; margin-left: 8px; }
.ssl-info { display: flex; flex-direction: column; gap: 12px; }
.ssl-info-item { display: flex; align-items: center; gap: 12px; }
.ssl-info-label { color: #999; width: 80px; flex-shrink: 0; font-size: 13px; }
.ssl-info-value { color: #333; flex: 1; font-size: 14px; }
</style>