<template>
  <div class="dev-page">
    <!-- 工具栏 -->
    <div class="page-toolbar">
      <div class="toolbar-left">
        <h3 class="page-title">SSL 证书管理</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="filterCertType" placeholder="证书类型" style="width: 120px" allow-clear @change="loadList">
          <a-select-option value="DV">DV 型</a-select-option>
          <a-select-option value="OV">OV 型</a-select-option>
          <a-select-option value="EV">EV 型</a-select-option>
        </a-select>
        <a-select v-model:value="filterStatus" placeholder="证书状态" style="width: 120px" allow-clear @change="loadList">
          <a-select-option value="valid">有效</a-select-option>
          <a-select-option value="expiring">即将到期</a-select-option>
          <a-select-option value="expired">已过期</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">
      <SafetyCertificateOutlined class="notice-icon" />
      <span>在此管理 SSL/TLS 证书，支持保护多个域名，提供自动到期提醒（<strong>私钥会使用 AES 加密存储</strong>）。</span>
    </div>

    <!-- SSL 证书卡片列表 -->
    <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="暂无 SSL 证书，点击添加按钮上传证书">
        <a-button type="primary" @click="showAdd = true"><template #icon><PlusOutlined /></template>添加证书</a-button>
      </a-empty>
    </div>
    <div v-else class="ssl-grid">
      <div v-for="item in list" :key="item.resourceId" class="ssl-card" :class="{ 'card-expiring': isNearExpiry(item.expireAt) }">
        <!-- 卡片头部 -->
        <div class="card-header">
          <div class="card-header-left">
            <div class="ssl-name" @click="copyText(item.name!)">
              <SafetyCertificateOutlined />
              <span class="ssl-text">{{ item.name }}</span>
              <CopyOutlined class="copy-icon" />
            </div>
            <div class="ssl-tags">
              <a-tag :color="certTypeColor[item.certType] || 'default'" size="small">{{ item.certType || '-' }}</a-tag>
              <a-tag :color="getStatusColor(item.status)" size="small">{{ certStatusLabel[item.status] || item.status }}</a-tag>
              <a-tag v-if="isNearExpiry(item.expireAt)" color="orange" size="small">即将到期</a-tag>
              <a-tag v-if="isExpired(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 key="viewDetails"><template #icon><EyeOutlined /></template>查看证书内容</a-menu-item>
                <a-menu-item key="copyCert"><template #icon><CopyOutlined /></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">绑定域名</span><span class="info-value domain-value" @click="copyText(item.domain!)">{{ item.domain || '-' }}<CopyOutlined class="copy-icon-small" /></span></div>
          <div class="info-row"><span class="info-label">颁发机构</span><span class="info-value">{{ item.issuer || '-' }}</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 class="info-row">
            <span class="info-label">安全状态</span>
            <span class="info-value">
              <template v-if="recordContainsPrivateKey(item)"><SafetyOutlined style="color: #52c41a; margin-right: 4px;" />私钥已保存</template>
              <template v-else-if="item.certificate"><SafetyOutlined style="color: #1890ff; margin-right: 4px;" />证书已保存</template>
              <span v-else class="text-muted">未配置</span>
            </span>
          </div>
          <!-- 协作者标识 -->
          <div v-if="!item.isOwner && !getAppPermission(item.appId)?.canEditResource" class="info-row">
            <span class="info-label"></span>
            <span class="info-value" style="font-size: 12px; color: #faad14;">
              <LockOutlined /> {{ (item.accessLevel ?? 1) >= 2 ? '协作者（开发者）' : '协作者（只读）' }}
            </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 size="small" @click="handleViewDetails(item)"><template #icon><EyeOutlined /></template>查看</a-button>
          <a-button v-if="item.certificate" size="small" @click="handleCopyCert(item)"><template #icon><CopyOutlined /></template>复制证书</a-button>
        </div>
      </div>
    </div>

    <!-- 分页 -->
    <div v-if="list.length > 0" class="card-pagination">
      <a-pagination
        v-model:current="pagination.current"
        v-model:pageSize="pagination.pageSize"
        :total="pagination.total"
        show-size-changer
        size="small"
        @change="loadList"
      />
    </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">
        <a-form-item label="证书名称" name="name">
          <a-input v-model:value="form.name" placeholder="如：example.com-ssl" />
        </a-form-item>
        <a-form-item label="绑定域名" name="domain">
          <a-input v-model:value="form.domain" placeholder="如：example.com 或 *.example.com（通配符）" />
        </a-form-item>
        <a-form-item label="证书类型" name="certType">
          <a-select v-model:value="form.certType" placeholder="请选择">
            <a-select-option value="DV">DV（域名验证型）</a-select-option>
            <a-select-option value="OV">OV（组织验证型）</a-select-option>
            <a-select-option value="EV">EV（扩展验证型）</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="颁发机构" name="issuer">
          <a-input v-model:value="form.issuer" placeholder="如：腾讯云 TrustAsia、Let's Encrypt" />
        </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="expireAt">
          <a-date-picker v-model:value="form.expireAt" value-format="YYYY-MM-DD" style="width: 100%" placeholder="选择证书到期日期" />
        </a-form-item>
        <a-form-item label="证书文件" name="certificate">
          <a-textarea v-model:value="form.certificate" :rows="4" placeholder="粘贴完整的证书内容（包含BEGIN/END标记）" :maxlength="8000" />
          <div style="margin-top: 4px; font-size: 12px; color: #999">支持 PEM 格式，建议直接复制证书文件内容</div>
          <div style="margin-top: 8px; display: flex; gap: 8px; flex-wrap: wrap;">
            <a-button size="small" type="link" @click="insertSampleCertificate" style="padding: 0; font-size: 12px;">
              <template #icon><CopyOutlined /></template>插入示例格式
            </a-button>
            <a-button size="small" type="link" @click="formatCertificate" style="padding: 0; font-size: 12px;">
              <template #icon><FormOutlined /></template>格式化证书
            </a-button>
            <a-button size="small" type="link" @click="validateCertificateInput" style="padding: 0; font-size: 12px;">
              <template #icon><CheckCircleOutlined /></template>检查格式
            </a-button>
          </div>
          <div v-if="certificateInfo" style="margin-top: 8px; padding: 8px; background: #f6ffed; border: 1px solid #b7eb8f; border-radius: 4px;">
            <div style="color: #52c41a; font-weight: 500; margin-bottom: 4px;">证书信息预览</div>
            <div style="font-size: 12px; color: #666;">
              <div style="margin-bottom: 2px;">域名: {{ certificateInfo.subject }}</div>
              <div style="margin-bottom: 2px;">颁发机构: {{ certificateInfo.issuer }}</div>
              <div style="margin-bottom: 2px;">有效期: {{ certificateInfo.validity }}</div>
              <div v-if="certificateInfo.hasDetectedExpiry && form.expireAt" style="margin-top: 8px; padding: 4px; background: #fffbe6; border: 1px dashed #faad14; border-radius: 2px;">
                <div style="color: #faad14; display: flex; align-items: center; gap: 4px;">
                  <CheckCircleOutlined style="font-size: 12px;" />
                  <span>已自动识别到期时间: {{ form.expireAt }}，保存时将入库</span>
                </div>
              </div>
            </div>
          </div>
        </a-form-item>
        <a-form-item label="私钥（敏感信息）" name="privateKey" :extra="privateKeyExtra">
          <a-textarea v-model:value="form.privateKey" :rows="4" placeholder="必填：粘贴完整的私钥内容（包含BEGIN/END标记，AES加密存储）" :maxlength="8000" />
          <div style="margin-top: 4px; font-size: 12px; color: #999">支持 PEM、PKCS#8 格式，私钥内容会自动加密存储</div>
          <div style="margin-top: 8px; display: flex; gap: 8px; flex-wrap: wrap;">
            <a-button size="small" type="link" @click="insertSamplePrivateKey" style="padding: 0; font-size: 12px;">
              <template #icon><CopyOutlined /></template>插入示例格式
            </a-button>
            <a-button size="small" type="link" @click="formatPrivateKey" style="padding: 0; font-size: 12px;">
              <template #icon><FormOutlined /></template>格式化私钥
            </a-button>
            <a-button size="small" type="link" @click="validatePrivateKeyInput" style="padding: 0; font-size: 12px;">
              <template #icon><CheckCircleOutlined /></template>检查格式
            </a-button>
          </div>
        </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, SafetyCertificateOutlined, GlobalOutlined, CopyOutlined, EllipsisOutlined, EditOutlined, DeleteOutlined, EyeOutlined, SafetyOutlined, LockOutlined, FormOutlined, CheckCircleOutlined } 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 } from '@/api/app/appResource/model'
import { enrichResourcesWithPermission } from '@/composables/useResourceAccess'

definePageMeta({ layout: 'developer' })
useHead({ title: 'SSL 证书管理 - 开发者中心' })

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

const form = reactive({
  name: '',
  domain: '',
  certType: undefined as string | undefined,
  issuer: 'Let\'s Encrypt', // 默认颁发机构
  certificate: '',
  privateKey: '',
  appId: undefined as number | undefined,
  expireAt: null as any,
  remark: '',
})

const hasCertificateContent = computed(() => form.certificate && form.certificate.trim().length > 0)
const hasPrivateKeyContent = computed(() => form.privateKey && form.privateKey.trim().length > 0)
const isValidCertificateFormat = computed(() => {
  if (!hasCertificateContent.value) return false
  const cert = form.certificate.trim()
  return cert.includes('-----BEGIN CERTIFICATE-----') && cert.includes('-----END CERTIFICATE-----')
})
const isValidPrivateKeyFormat = computed(() => {
  if (!hasPrivateKeyContent.value) return false
  const key = form.privateKey.trim()
  return key.includes('-----BEGIN') && (key.includes('PRIVATE KEY-----') || key.includes('RSA PRIVATE KEY-----') || key.includes('ENCRYPTED PRIVATE KEY-----'))
})

const privateKeyExtra = computed(() => {
  if (editRecord.value) {
    if (form.privateKey === '[私钥已保存]') {
      return '显示的"[私钥已保存]"为占位符，实际私钥会保留；如需修改私钥，请完整输入新的私钥内容'
    }
    return '如需修改私钥，请完整输入新的私钥内容；如需保留原私钥，请勿更改此字段'
  }
  return '请粘贴完整的私钥内容（包含BEGIN/END标记），此字段为必填，新增证书必须提供私钥'
})

const filterCertType = ref<string>()
const filterStatus = ref<string>()

// 证书信息解析
const certificateInfo = computed(() => {
  if (!form.certificate || !form.certificate.trim()) {
    return { subject: '-', issuer: '-', validity: '-' }
  }

  try {
    const certContent = form.certificate.trim()
    
    // 尝试解析证书内容
    let subject = '-'
    let issuer = '-'
    let validity = '-'
    let detectedExpiry = null
    
    // 去除多余的空行和空格
    const cleanContent = certContent.replace(/\r\n/g, '\n').replace(/\s+/g, ' ')
    
    // 尝试多种格式提取主题（Subject）
    let subjectMatch = cleanContent.match(/Subject:(.*?)(?:\n|$)/)
    if (!subjectMatch) {
      // 尝试其他格式
      subjectMatch = cleanContent.match(/CN=(.*?)(?:\s|,|$)/)
    }
    if (subjectMatch) {
      subject = subjectMatch[1].trim()
    }
    
    // 尝试多种格式提取颁发者（Issuer）
    let issuerMatch = cleanContent.match(/Issuer:(.*?)(?:\n|$)/)
    if (!issuerMatch) {
      issuerMatch = cleanContent.match(/O=(.*?)(?:\s|,|$)/)
    }
    if (issuerMatch) {
      issuer = issuerMatch[1].trim()
    }
    
    // 尝试多种格式提取有效期（Not Before / Not After）
    const notBeforePatterns = [
      /Not Before\s*:\s*(.*?)(?:\n|$)/i,
      /NotBefore\s*:\s*(.*?)(?:\n|$)/i,
      /Validity\s*Not Before\s*:\s*(.*?)(?:\n|$)/i,
    ]
    
    const notAfterPatterns = [
      /Not After\s*:\s*(.*?)(?:\n|$)/i,
      /NotAfter\s*:\s*(.*?)(?:\n|$)/i,
      /Validity\s*Not After\s*:\s*(.*?)(?:\n|$)/i,
    ]
    
    let notBefore = null
    let notAfter = null
    
    for (const pattern of notBeforePatterns) {
      const match = cleanContent.match(pattern)
      if (match) {
        notBefore = match[1].trim()
        break
      }
    }
    
    for (const pattern of notAfterPatterns) {
      const match = cleanContent.match(pattern)
      if (match) {
        notAfter = match[1].trim()
        break
      }
    }
    
    if (notBefore && notAfter) {
      validity = `${notBefore} 至 ${notAfter}`
      
      // 解析到期时间，自动设置到表单的 expireAt 字段
      if (notAfter) {
        // 尝试多种日期格式解析
        const dateFormats = [
          // RFC 格式: Apr  6 05:26:00 2026 GMT
          { pattern: /([A-Za-z]+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)\s+GMT/, 
            handler: (match: RegExpMatchArray) => {
              const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
              const month = months.indexOf(match[1]) + 1
              const day = parseInt(match[2])
              const year = parseInt(match[6])
              return new Date(year, month - 1, day)
            }
          },
          // ISO 格式: 2026-04-06T05:26:00Z
          { pattern: /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z/, 
            handler: (match: RegExpMatchArray) => {
              const year = parseInt(match[1])
              const month = parseInt(match[2])
              const day = parseInt(match[3])
              return new Date(year, month - 1, day)
            }
          },
          // 简单日期格式: 2026-04-06
          { pattern: /(\d{4})-(\d{2})-(\d{2})/, 
            handler: (match: RegExpMatchArray) => {
              const year = parseInt(match[1])
              const month = parseInt(match[2])
              const day = parseInt(match[3])
              return new Date(year, month - 1, day)
            }
          },
        ]
        
        let expiryDate = null
        for (const format of dateFormats) {
          const match = notAfter.match(format.pattern)
          if (match) {
            try {
              expiryDate = format.handler(match)
              if (expiryDate && !isNaN(expiryDate.getTime())) {
                break
              }
            } catch (e) {
              // 继续尝试下一个格式
              continue
            }
          }
        }
        
        if (expiryDate && !isNaN(expiryDate.getTime())) {
          // 格式化为 YYYY-MM-DD 格式
          const year = expiryDate.getFullYear()
          const month = String(expiryDate.getMonth() + 1).padStart(2, '0')
          const day = String(expiryDate.getDate()).padStart(2, '0')
          const expiryStr = `${year}-${month}-${day}`
          
          // 只在确实识别到新时间时才更新，避免覆盖用户手动输入
          if (!form.expireAt || form.expireAt !== expiryStr) {
            form.expireAt = expiryStr
            detectedExpiry = expiryStr
            
            // 如果表单正在编辑，提示用户
            if (editRecord.value) {
              console.log('检测到证书到期时间:', expiryStr, '已自动更新到期时间字段')
            }
          }
        }
      }
    }
    
    return { 
      subject, 
      issuer, 
      validity,
      hasDetectedExpiry: !!detectedExpiry
    }
  } catch (error) {
    console.warn('证书解析失败:', error)
    return { subject: '-', issuer: '-', validity: '-', hasDetectedExpiry: false }
  }
})

const validatePrivateKey = (_: any, value: string) => {
  // 新增模式：必须提供私钥内容
  if (!editRecord.value) {
    if (!value || !value.trim()) {
      return Promise.reject(new Error('新增证书必须提供私钥内容'))
    }
    // 检查格式是否基本正确（包含BEGIN标记）
    const trimmed = value.trim()
    if (!trimmed.includes('-----BEGIN')) {
      return Promise.reject(new Error('私钥格式不正确，应包含BEGIN标记'))
    }
    return Promise.resolve()
  }
  
  // 编辑模式：允许显示"[私钥已保存]"或新输入的私钥
  if (!value || !value.trim() || value === '[私钥已保存]') {
    // 空值或占位符表示保留原私钥
    return Promise.resolve()
  }
  
  // 如果用户输入了新内容，检查格式
  const trimmed = value.trim()
  if (!trimmed.includes('-----BEGIN')) {
    return Promise.reject(new Error('私钥格式不正确，应包含BEGIN标记'))
  }
  
  return Promise.resolve()
}

const rules = {
  name: [{ required: true, message: '请输入证书名称' }],
  domain: [{ required: true, message: '请输入绑定域名' }],
  certType: [{ required: true, message: '请选择证书类型' }],
  certificate: [{ required: true, message: '请输入证书内容' }],
  privateKey: [{ validator: validatePrivateKey }],
}

const certStatusLabel: Record<string, string> = {
  valid: '有效',
  expired: '已过期',
  expiring: '即将过期',
  running: '有效',
  stopped: '已停用',
  pending: '配置中',
}

const certTypeColor: Record<string, string> = {
  DV: 'blue',
  OV: 'purple',
  EV: 'gold',
}



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

function isNearExpiry(dateStr: string): boolean {
  if (!dateStr || dateStr === '-') return false
  return dayjs(dateStr).diff(dayjs(), 'day') <= 30
}

function isExpired(dateStr: string): boolean {
  if (!dateStr || dateStr === '-') return false
  return dayjs(dateStr).isBefore(dayjs(), 'day')
}

function getStatusColor(status: string | undefined): string {
  switch (status) {
    case 'valid': return 'green'
    case 'expiring': return 'orange'
    case 'expired': return 'red'
    default: return 'default'
  }
}

function handleMenuAction(key: string, record: AppResource) {
  switch (key) {
    case 'edit':
      handleEdit(record)
      break
    case 'viewDetails':
      handleViewDetails(record)
      break
    case 'copyCert':
      handleCopyCert(record)
      break
    case 'delete':
      handleDelete(record.resourceId!)
      break
  }
}

function recordContainsPrivateKey(record: AppResource): boolean {
  // 检查记录是否包含私钥（通过后端字段或内容判断）
  return !!record.privateKey && record.privateKey.trim().length > 0 && record.privateKey.includes('-----BEGIN')
}

function copyText(text: string) {
  navigator.clipboard.writeText(text)
    .then(() => message.success('已复制到剪贴板'))
    .catch(() => message.error('复制失败'))
}

function handleViewDetails(record: AppResource) {
  // 查看证书详细信息
  const certContent = record.certificate || '无证书内容'
  const modal = Modal.info({
    title: `证书详情 - ${record.name}`,
    width: 800,
    content: (
      `<div style="max-height: 400px; overflow: auto; font-family: monospace;">
        <pre style="margin: 0; font-size: 12px;">${certContent}</pre>
      </div>`
    ),
    okText: '关闭',
    onOk() {
      modal.destroy()
    },
  })
}

function handleCopyCert(record: AppResource) {
  if (record.certificate) {
    copyText(record.certificate)
  } else {
    message.warning('证书内容为空')
  }
}

function insertSampleCertificate() {
  form.certificate = `-----BEGIN CERTIFICATE-----
MIIDYTCCAkWgAwIBAgIQDlRj+E8dQq1TjMh+9f2BmH1TANBgkqhkiG9w0BAQsFADBZ
MQswCQYDVQQGEwJDTjEQMA4GA1UECBMHQmVpamluZzEQMA4GA1UEBxMHQmVpamlu
ZzEUMBIGA1UEChMLRXhhbXBsZSBMTEMxEjAQBgNVBAMTCWV4YW1wbGUuY29tMB4X
DTI0MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowWTELMAkGA1UEBhMCQ04xEDAO
BgNVBAgTB0JlaWppbmcxEDAOBgNVBAcTB0JlaWppbmcxFDASBgNVBAoTC0V4YW1w
bGUgTExDMRIwEAYDVQQDEwlleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBALR8K7T5e4H5VKtVrN7lzQ7X8N9ZQwKpXqKp4j9Yw+2WqW9
tL8fQ5xZbJN0jK7z8+QpzL7zL8fQ5xZbJN0jK7z8+QpzL7zL8fQ5xZbJN0jK7z
8+QpzL7zL8fQ5xZbJN0jK7z8+QpzL7zL8fQ5xZbJN0jK7z8+QpzL7zL8fQ5xZb
JN0jK7z8+QpzL7zL8fQ5xZbJN0jK7z8+QpzL7zL8fQ5xZbJN0jK7z8+QpzL7zL
8fQ5xZbJN0jK7z8+QpzL7zL8fQ5xZbJN0jK7z8+QpzL7zL8fQ5xZbJN0jK7z8+
-----END CERTIFICATE-----`
  message.info('已插入示例证书格式')
}

function insertSamplePrivateKey() {
  form.privateKey = `-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC0fCu0+XuB+VSr
Vaze5c0O1/DfWUMCqV6iqeI/WMPtlqlvbS/H0OcWWyTdIyu8/PkKcy+8y/H0OcW
WyTdIyu8/PkKcy+8y/H0OcWWyTdIyu8/PkKcy+8y/H0OcWWyTdIyu8/PkKcy+8y
/H0OcWWyTdIyu8/PkKcy+8y/H0OcWWyTdIyu8/PkKcy+8y/H0OcWWyTdIyu8/Pk
Kcy+8y/H0OcWWyTdIyu8/PkKcy+8y/H0OcWWyTdIyu8/PkKcy+8y/H0OcWWyTdI
yu8/PkKcy+8y/H0OcWWyTdIyu8/PkKcy+8y/H0OcWWyTdIyu8/PkKcy+8y/H0Oc
-----END PRIVATE KEY-----`
  message.info('已插入示例私钥格式')
}

// 格式清理功能
function formatCertificate() {
  if (!form.certificate) return
  // 移除多余的空格和换行
  let cert = form.certificate.trim()
  // 确保 BEGIN 和 END 标记在单独的行
  cert = cert.replace(/-----BEGIN CERTIFICATE-----\s*/g, '-----BEGIN CERTIFICATE-----\n')
  cert = cert.replace(/\s*-----END CERTIFICATE-----/g, '\n-----END CERTIFICATE-----')
  form.certificate = cert
  message.success('证书格式已优化')
}

function formatPrivateKey() {
  if (!form.privateKey) return
  // 移除多余的空格和换行
  let key = form.privateKey.trim()
  // 确保 BEGIN 和 END 标记在单独的行
  key = key.replace(/-----BEGIN [\w\s]+-----\s*/g, (match) => match + '\n')
  key = key.replace(/\s*-----END [\w\s]+-----/g, '\n-----END')
  form.privateKey = key
  message.success('私钥格式已优化')
}

function validatePrivateKeyInput() {
  if (!form.privateKey || !form.privateKey.trim()) {
    message.warning('请输入私钥内容后再检查格式')
    return
  }
  
  const trimmed = form.privateKey.trim()
  const hasBegin = trimmed.includes('-----BEGIN')
  const hasPrivateKeyEnd = trimmed.includes('PRIVATE KEY-----') || trimmed.includes('RSA PRIVATE KEY-----') || trimmed.includes('ENCRYPTED PRIVATE KEY-----')
  
  if (hasBegin && hasPrivateKeyEnd) {
    message.success('私钥格式正确')
  } else if (!hasBegin && !hasPrivateKeyEnd) {
    message.warning('私钥缺少 BEGIN 和 PRIVATE KEY 标记')
  } else if (!hasBegin) {
    message.warning('私钥缺少 BEGIN 标记')
  } else {
    message.warning('私钥缺少 PRIVATE KEY 标记')
  }
}

// 输入校验提示
function validateCertificateInput() {
  if (!form.certificate || !form.certificate.trim()) {
    message.warning('请输入证书内容后再检查格式')
    return
  }
  
  const cert = form.certificate.trim()
  const hasBegin = cert.includes('-----BEGIN CERTIFICATE-----')
  const hasEnd = cert.includes('-----END CERTIFICATE-----')
  
  if (hasBegin && hasEnd) {
    message.success('证书格式正确')
  } else if (!hasBegin && !hasEnd) {
    message.warning('证书缺少 BEGIN 和 END 标记')
  } else if (!hasBegin) {
    message.warning('证书缺少 BEGIN CERTIFICATE 标记')
  } else {
    message.warning('证书缺少 END CERTIFICATE 标记')
  }
}

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

async function loadList() {
  loading.value = true
  try {
    // 构建过滤参数
    const filterParams: any = {
      resourceType: 'ssl',
      keywords: searchText.value || undefined,
      appId: selectedAppId.value,
      certType: filterCertType.value,
      page: pagination.current,
      limit: pagination.pageSize,
    }

    // 状态过滤（简化处理）
    if (filterStatus.value === 'valid') {
      filterParams.status = 'valid'
    } else if (filterStatus.value === 'expired') {
      filterParams.status = 'expired'
    } else if (filterStatus.value === 'expiring') {
      // 即将到期的需要在客户端过滤
      filterParams.status = 'valid' // 先加载有效的
    }

    const result = await pageAppResource(filterParams)
    let filteredList = enrichResourcesWithPermission(result?.list ?? [])
    
    // 客户端过滤：即将到期的证书
    if (filterStatus.value === 'expiring') {
      filteredList = filteredList.filter(item => isNearExpiry(item.expireAt!))
    }

    list.value = filteredList
    pagination.total = filterStatus.value === 'expiring' ? filteredList.length : (result?.count ?? 0)
  }
  catch (e: any) {
    message.error(e.message || '加载失败')
  }
  finally {
    loading.value = false
  }
}

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

function handleEdit(record: AppResource) {
  if (!record.isOwner) {
    message.warning('只有证书创建者才能编辑')
    return
  }
  editRecord.value = record
  
  // 检查是否有私钥
  const hasPrivateKey = record.privateKey && record.privateKey.trim().length > 0
  
  Object.assign(form, {
    name: record.name,
    domain: record.domain,
    certType: record.certType,
    issuer: record.issuer || '',
    certificate: record.certificate || '',
    privateKey: hasPrivateKey ? '[私钥已保存]' : '', // 编辑时显示提示，不显示实际私钥内容
    appId: record.appId ? Number(record.appId) : undefined,
    expireAt: record.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('已移除')
    loadList()
  }
  catch (e: any) {
    message.error(e.message || '删除失败')
  }
}

async function handleSave() {
  await formRef.value?.validate()
  saveLoading.value = true
  try {
    // 检查证书格式
    if (form.certificate && !isValidCertificateFormat.value) {
      message.warning('证书格式可能不正确，请确认包含正确的 BEGIN/END 标记')
    }

    const payload: AppResource = {
      resourceType: 'ssl',
      name: form.name,
      domain: form.domain,
      certType: form.certType,
      issuer: form.issuer || undefined,
      certificate: form.certificate,
      privateKey: form.privateKey || undefined,
      publicKey: '', // 后端可能需要这个字段，即使为空
      appId: form.appId ? Number(form.appId) : undefined,
      expireAt: form.expireAt ? dayjs(form.expireAt).format('YYYY-MM-DD') : undefined,
      remark: form.remark || undefined,
    }

    // 处理私钥字段：如果是编辑模式且用户输入了"[私钥已保存]"或空值，则保留原私钥
    if (editRecord.value) {
      payload.resourceId = editRecord.value.resourceId
      // 保持原有的publicKey值（如果有的话）
      payload.publicKey = editRecord.value.publicKey || ''
      
      // 判断是否需要保留原私钥
      const privateKeyValue = form.privateKey.trim()
      if (privateKeyValue === '[私钥已保存]' || !privateKeyValue) {
        // 保留原私钥，不更新privateKey字段
        if (payload.privateKey !== undefined) {
          delete payload.privateKey
        }
      } else {
        // 用户输入了新私钥，使用新值
        payload.privateKey = privateKeyValue
      }
      
      await updateAppResource(payload)
      message.success('保存成功')
    }
    else {
      // 新增模式：私钥已在验证器中检查过格式
      await addAppResource(payload)
      message.success('证书添加成功')
    }
    showAdd.value = false
    resetForm()
    loadList()
  }
  catch (e: any) {
    console.error('SSL证书保存失败:', e)
    if (e.response?.data?.message) {
      message.error(e.response.data.message)
    } else if (e.message && e.message !== 'Network Error') {
      message.error(e.message)
    } else {
      message.error('保存失败，请检查网络连接和表单填写')
    }
  }
  finally {
    saveLoading.value = false
  }
}

function resetForm() {
  editRecord.value = null
  formRef.value?.resetFields()
  Object.assign(form, {
    name: '',
    domain: '',
    certType: undefined,
    issuer: 'Let\'s Encrypt', // 重置时也使用默认值
    certificate: '',
    privateKey: '',
    appId: undefined,
    expireAt: null,
    remark: '',
  })
}

onMounted(() => {
  loadAppOptions()
  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;
  color: rgba(0, 0, 0, 0.85);
}
.toolbar-right {
  display: flex;
  gap: 12px;
  align-items: center;
}

/* 通知栏 */
.notice-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  background: linear-gradient(90deg, #f0f7ff 0%, #e6f4ff 100%);
  border: 1px solid #91caff;
  border-radius: 8px;
  padding: 12px 18px;
  margin-bottom: 24px;
  font-size: 14px;
  color: #1677ff;
}
.notice-icon {
  font-size: 16px;
  color: #1677ff;
}
.notice-bar strong {
  color: #0958d9;
}

/* 卡片布局 */
.ssl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
  gap: 20px;
  margin-bottom: 24px;
}
.ssl-card {
  background: #fff;
  border: 1px solid #f0f0f0;
  border-radius: 12px;
  padding: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
  transition: all 0.2s ease;
}
.ssl-card:hover {
  border-color: #d9d9d9;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.card-expiring {
  border-color: #ffd591;
  background: linear-gradient(145deg, #fffbe6, #fff2cc);
}

/* 卡片头部 */
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 16px;
}
.card-header-left {
  flex: 1;
}
.ssl-name {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: color 0.2s;
}
.ssl-name:hover {
  color: #1890ff;
}
.ssl-text {
  font-weight: 600;
  font-size: 16px;
  color: rgba(0, 0, 0, 0.85);
}
.copy-icon {
  color: #8c8c8c;
  font-size: 13px;
  opacity: 0.6;
  transition: opacity 0.2s;
}
.ssl-name:hover .copy-icon {
  opacity: 1;
}
.ssl-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}

/* 卡片信息区 */
.card-info {
  margin-bottom: 16px;
}
.info-row {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
  font-size: 13px;
}
.info-label {
  flex: 0 0 70px;
  color: rgba(0, 0, 0, 0.45);
}
.info-value {
  flex: 1;
  color: rgba(0, 0, 0, 0.85);
  word-break: break-all;
}
.domain-value {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
}
.domain-value:hover {
  color: #1890ff;
}
.copy-icon-small {
  font-size: 11px;
  color: #8c8c8c;
}
.text-muted {
  color: rgba(0, 0, 0, 0.25);
}
.text-warning {
  color: #fa8c16;
  font-weight: 500;
}
.text-danger {
  color: #f5222d;
  font-weight: 500;
}

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

/* 加载和空状态 */
.card-loading {
  text-align: center;
  padding: 60px 0;
}
.card-empty {
  text-align: center;
  padding: 80px 0;
}

/* 分页 */
.card-pagination {
  display: flex;
  justify-content: center;
  margin-top: 20px;
}

/* 表单样式 */
.form-row-2 {
  display: flex;
  gap: 16px;
  margin-bottom: 16px;
}
.form-item-half {
  flex: 1;
}

/* 表单输入框盒子 */
.input-box {
  border: 1px solid #f0f0f0;
  border-radius: 8px;
  padding: 12px;
  background: #fafafa;
}
.certificate-box {
  border-color: #b7eb8f;
  background: #f6ffed;
}
.private-key-box {
  border-color: #ffd591;
  background: #fffbe6;
}
.input-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  font-size: 14px;
  font-weight: 500;
}
.security-notice {
  font-size: 12px;
  color: #fa8c16;
  display: flex;
  align-items: center;
}
.certificate-preview {
  margin-top: 12px;
  padding: 12px;
  background: #e6fffb;
  border: 1px solid #87e8de;
  border-radius: 6px;
}
.preview-header {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
  font-size: 14px;
  font-weight: 500;
  color: #08979c;
}
.security-tip {
  margin-top: 8px;
  padding: 8px;
  background: #f0f7ff;
  border: 1px solid #91caff;
  border-radius: 4px;
  font-size: 12px;
  color: #1677ff;
  display: flex;
  align-items: center;
}

/* 安全卡片 */
.security-card {
  display: flex;
  align-items: center;
  padding: 16px;
  background: #f0f7ff;
  border: 1px solid #91caff;
  border-radius: 8px;
}

/* 可选提示 */
.optional-notice {
  font-size: 12px;
  color: rgba(0, 0, 0, 0.45);
  margin-bottom: 4px;
}
</style>
