<template>
  <div v-if="app">
    <el-page-header @back="$router.back()" content="推送服务配置" style="margin-bottom:24px" />

    <el-card class="info-card" style="margin-bottom:16px">
      <el-descriptions :column="isMobile ? 1 : 2" border>
        <el-descriptions-item label="应用名称">{{ app.name }}</el-descriptions-item>
        <el-descriptions-item label="包名">{{ app.packageName }}</el-descriptions-item>
        <el-descriptions-item label="AppKey">
          <el-text class="mono">{{ app.appKey }}</el-text>
          <el-button link @click="copy(app.appKey)"><el-icon><CopyDocument /></el-icon></el-button>
        </el-descriptions-item>
        <el-descriptions-item label="服务状态">
          <el-tag :type="pushEnabled ? 'success' : 'info'">{{ pushEnabled ? '已开通' : '未开通' }}</el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="配置平台">
          <el-segmented v-model="selectedPlatform" :options="platformOptions" @change="applySelectedPlatformConfig" />
        </el-descriptions-item>
      </el-descriptions>
      <div class="push-switch-row">
        <el-switch :model-value="pushEnabled" @change="(val: boolean) => onTogglePushService(val)" />
        <span class="hint">关闭后，推送注册与推送发送都不会再向该应用开放。</span>
      </div>
    </el-card>

    <el-alert
      title="这里维护各厂商推送凭据。推送服务开通后，离线推送才会按厂商路由发送。"
      type="info"
      :closable="false"
      show-icon
      style="margin-bottom:16px"
    />

    <el-card>
      <template #header>厂商配置</template>
      <el-divider content-position="left">通知通道</el-divider>
      <el-alert
        description="通知通道定义 Android 通知渠道，以及 iOS/鸿蒙 对应的分类配置。业务键（Key）为业务层自定义的唯一标识，代码内部用于引用此通道，例如 im_message；Channel ID 需与 App manifest 中声明的 NotificationChannel ID 完全一致；版本号在渠道参数变更时自增，客户端将以新版本号重新注册渠道。"
        type="info"
        :closable="false"
        :show-icon="false"
        style="margin-bottom:12px"
      />
      <el-table :data="pushConfig.channels" border style="margin-bottom:16px">
        <el-table-column label="业务键" min-width="130">
          <template #default="{ row }">
            <el-input v-model="row.key" />
          </template>
        </el-table-column>
        <el-table-column label="Channel ID" min-width="180">
          <template #default="{ row }">
            <el-input v-model="row.channelId" />
          </template>
        </el-table-column>
        <el-table-column label="版本" width="82">
          <template #default="{ row }">
            <el-input-number v-model="row.version" :min="1" controls-position="right" style="width:72px" />
          </template>
        </el-table-column>
        <el-table-column label="名称" min-width="130">
          <template #default="{ row }">
            <el-input v-model="row.name" />
          </template>
        </el-table-column>
        <el-table-column label="重要性" width="130">
          <template #default="{ row }">
            <el-select v-model="row.importance">
              <el-option v-for="item in importanceOptions" :key="item.value" :label="item.label" :value="item.value" />
            </el-select>
          </template>
        </el-table-column>
        <el-table-column label="声音" width="80" align="center">
          <template #default="{ row }"><el-switch v-model="row.sound" /></template>
        </el-table-column>
        <el-table-column label="振动" width="80" align="center">
          <template #default="{ row }"><el-switch v-model="row.vibration" /></template>
        </el-table-column>
        <el-table-column label="角标" width="80" align="center">
          <template #default="{ row }"><el-switch v-model="row.badge" /></template>
        </el-table-column>
        <el-table-column label="操作" width="80">
          <template #default="{ $index }">
            <el-button link type="danger" @click="removeChannel($index)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-button style="margin-bottom:20px" @click="addChannel">新增通道</el-button>

      <el-divider content-position="left">业务分类路由</el-divider>
      <el-alert
        description="业务分类路由将系统内置的推送类型（如 IM 消息、好友请求、系统通知）映射到对应通道和优先级，决定推送到达时的展示行为。"
        type="info"
        :closable="false"
        :show-icon="false"
        style="margin-bottom:12px"
      />
      <el-table :data="routeRows" border style="margin-bottom:20px">
        <el-table-column label="业务分类" width="160">
          <template #default="{ row }">{{ row.type }}</template>
        </el-table-column>
        <el-table-column label="通道" min-width="180">
          <template #default="{ row }">
            <el-select v-model="row.route.channel">
              <el-option v-for="channel in pushConfig.channels" :key="channel.key" :label="channel.name || channel.key" :value="channel.key" />
            </el-select>
          </template>
        </el-table-column>
        <el-table-column label="Category" min-width="160">
          <template #default="{ row }">
            <el-input v-model="row.route.category" />
          </template>
        </el-table-column>
        <el-table-column label="优先级" width="130">
          <template #default="{ row }">
            <el-select v-model="row.route.priority">
              <el-option label="低" value="LOW" />
              <el-option label="默认" value="DEFAULT" />
              <el-option label="高" value="HIGH" />
            </el-select>
          </template>
        </el-table-column>
      </el-table>

      <el-divider content-position="left">厂商凭据</el-divider>
      <div class="vendor-grid">
        <el-card v-for="vendor in vendorDefs" :key="vendor.key" shadow="never" class="vendor-card">
          <template #header>{{ vendor.label }}</template>
          <div class="vendor-hint">{{ vendor.hint }}</div>
          <el-form :label-position="isMobile ? 'top' : 'right'" label-width="120px">
            <el-form-item v-for="field in vendor.fields" :key="field.key" :label="field.label">
              <el-input
                v-if="field.type === 'textarea'"
                v-model="pushConfig[vendor.key][field.key]"
                type="textarea"
                :rows="field.rows ?? 4"
                :placeholder="field.placeholder"
              />
              <el-switch
                v-else-if="field.type === 'switch'"
                v-model="pushConfig[vendor.key][field.key]"
              />
              <el-input
                v-else
                v-model="pushConfig[vendor.key][field.key]"
                type="text"
                :placeholder="field.placeholder"
              />
            </el-form-item>
          </el-form>
        </el-card>
      </div>

      <div class="toolbar">
        <el-button @click="reloadConfig" :loading="loading">刷新</el-button>
        <el-button type="primary" @click="saveConfig" :loading="saving">保存配置</el-button>
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { CopyDocument } from '@element-plus/icons-vue'
import {
  appApi,
  type App,
  type FeatureService,
  type PushNotificationChannelConfig,
  type PushNotificationRouteConfig,
  type PushServiceConfig,
} from '@/api/app'

type VendorKey = keyof PushServiceConfig
type FieldDef = {
  key: string
  label: string
  type?: 'textarea' | 'switch'
  placeholder?: string
  rows?: number
}
type VendorDef = {
  key: VendorKey
  label: string
  hint: string
  fields: FieldDef[]
}

const route = useRoute()
const app = ref<App | null>(null)
const services = ref<FeatureService[]>([])
const loading = ref(false)
const saving = ref(false)
const isMobile = ref(window.innerWidth < 768)
const selectedPlatform = ref<'ANDROID' | 'IOS' | 'HARMONY'>('ANDROID')
const platformOptions = [
  { label: 'Android', value: 'ANDROID' },
  { label: 'iOS', value: 'IOS' },
  { label: '鸿蒙', value: 'HARMONY' },
]

function updateViewport() {
  isMobile.value = window.innerWidth < 768
}

const pushConfig = reactive<Required<PushServiceConfig>>({
  huawei: { appId: '', appSecret: '' },
  xiaomi: { appId: '', appKey: '', appSecret: '' },
  oppo: { appId: '', appKey: '', masterSecret: '' },
  vivo: { appId: '', appKey: '', appSecret: '' },
  honor: { appId: '', clientId: '', clientSecret: '' },
  harmony: { appId: '', appSecret: '' },
  apns: { teamId: '', keyId: '', bundleId: '', keyPath: '', sandbox: false },
  fcm: { serviceAccountJson: '' },
  channels: defaultChannels(),
  routing: defaultRouting(),
} as Required<PushServiceConfig>)
const originalChannels = ref<PushNotificationChannelConfig[]>([])

const importanceOptions = [
  { label: '最小', value: 'MIN' },
  { label: '低', value: 'LOW' },
  { label: '默认', value: 'DEFAULT' },
  { label: '高', value: 'HIGH' },
  { label: '最高', value: 'MAX' },
] as const

const routeTypes = [
  { type: 'IM_MESSAGE', channel: 'im_message', category: 'MESSAGE', priority: 'HIGH' },
  { type: 'FRIEND_REQUEST', channel: 'im_message', category: 'SOCIAL', priority: 'HIGH' },
  { type: 'SYSTEM_NOTICE', channel: 'system_notice', category: 'SYSTEM', priority: 'DEFAULT' },
] as const

const routeRows = computed(() => routeTypes.map(item => ({
  type: item.type,
  route: pushConfig.routing[item.type] ?? ensureRoute(item.type, item.channel, item.category, item.priority),
})))

const vendorDefs: VendorDef[] = [
  {
    key: 'huawei',
    label: '华为 HMS',
    hint: '填写 AppId / AppSecret，供服务端推送使用。',
    fields: [
      { key: 'appId', label: 'AppId' },
      { key: 'appSecret', label: 'AppSecret' },
    ],
  },
  {
    key: 'xiaomi',
    label: '小米 MiPush',
    hint: '填写 AppId / AppKey / AppSecret。',
    fields: [
      { key: 'appId', label: 'AppId' },
      { key: 'appKey', label: 'AppKey' },
      { key: 'appSecret', label: 'AppSecret' },
    ],
  },
  {
    key: 'oppo',
    label: 'OPPO 推送',
    hint: '填写 AppId / AppKey / MasterSecret。',
    fields: [
      { key: 'appId', label: 'AppId' },
      { key: 'appKey', label: 'AppKey' },
      { key: 'masterSecret', label: 'MasterSecret' },
    ],
  },
  {
    key: 'vivo',
    label: 'vivo 推送',
    hint: '填写 AppId / AppKey / AppSecret。',
    fields: [
      { key: 'appId', label: 'AppId' },
      { key: 'appKey', label: 'AppKey' },
      { key: 'appSecret', label: 'AppSecret' },
    ],
  },
  {
    key: 'honor',
    label: '荣耀推送',
    hint: '填写 AppId / ClientId / ClientSecret。',
    fields: [
      { key: 'appId', label: 'AppId' },
      { key: 'clientId', label: 'ClientId' },
      { key: 'clientSecret', label: 'ClientSecret' },
    ],
  },
  {
    key: 'harmony',
    label: '鸿蒙 Push Kit',
    hint: '填写 HarmonyOS Push Kit AppId / AppSecret。',
    fields: [
      { key: 'appId', label: 'AppId' },
      { key: 'appSecret', label: 'AppSecret' },
    ],
  },
  {
    key: 'apns',
    label: 'APNs（iOS）',
    hint: '填写 Team ID / Key ID / Bundle ID / p8 文件路径。',
    fields: [
      { key: 'teamId', label: 'Team ID' },
      { key: 'keyId', label: 'Key ID' },
      { key: 'bundleId', label: 'Bundle ID' },
      { key: 'keyPath', label: 'p8 文件路径' },
      { key: 'sandbox', label: 'Sandbox', type: 'switch' },
    ],
  },
]

const pushEnabled = computed(() => services.value.some(
  s => s.serviceType === 'PUSH' && s.platform === selectedPlatform.value && s.enabled,
))
const servicePlatform = computed(() => selectedPlatform.value)

async function loadData() {
  const id = route.params.appId as string
  const [appRes, svcRes] = await Promise.all([
    appApi.get(id),
    appApi.getServices(id),
  ])
  app.value = appRes.data.data
  services.value = svcRes.data.data
  const firstPushService = services.value.find(s => s.serviceType === 'PUSH')
  if (firstPushService && !services.value.some(s => s.serviceType === 'PUSH' && s.platform === selectedPlatform.value)) {
    selectedPlatform.value = firstPushService.platform
  }
  applySelectedPlatformConfig()
}

function applySelectedPlatformConfig() {
  applyConfig(services.value.find(
    s => s.serviceType === 'PUSH' && s.platform === selectedPlatform.value,
  )?.config)
}

function applyConfig(raw?: string | null) {
  resetPushConfig()
  const parsed = parseConfig(raw)
  pushConfig.huawei = { ...pushConfig.huawei, ...parsed.huawei }
  pushConfig.xiaomi = { ...pushConfig.xiaomi, ...parsed.xiaomi }
  pushConfig.oppo = { ...pushConfig.oppo, ...parsed.oppo }
  pushConfig.vivo = { ...pushConfig.vivo, ...parsed.vivo }
  pushConfig.honor = { ...pushConfig.honor, ...parsed.honor }
  pushConfig.harmony = { ...pushConfig.harmony, ...parsed.harmony }
  pushConfig.apns = { ...pushConfig.apns, ...parsed.apns }
  pushConfig.fcm = { ...pushConfig.fcm, ...parsed.fcm }
  pushConfig.channels = normalizeChannels(parsed.channels)
  pushConfig.routing = normalizeRouting(parsed.routing)
  originalChannels.value = pushConfig.channels.map(channel => ({ ...channel }))
}

function resetPushConfig() {
  pushConfig.huawei = { appId: '', appSecret: '' }
  pushConfig.xiaomi = { appId: '', appKey: '', appSecret: '' }
  pushConfig.oppo = { appId: '', appKey: '', masterSecret: '' }
  pushConfig.vivo = { appId: '', appKey: '', appSecret: '' }
  pushConfig.honor = { appId: '', clientId: '', clientSecret: '' }
  pushConfig.harmony = { appId: '', appSecret: '' }
  pushConfig.apns = { teamId: '', keyId: '', bundleId: '', keyPath: '', sandbox: false }
  pushConfig.fcm = { serviceAccountJson: '' }
  pushConfig.channels = defaultChannels()
  pushConfig.routing = defaultRouting()
}

function parseConfig(raw?: string | null): PushServiceConfig {
  if (!raw) return {}
  try {
    return JSON.parse(raw) as PushServiceConfig
  } catch {
    return {}
  }
}

async function saveConfig() {
  if (!app.value) return
  saving.value = true
  try {
    bumpChangedChannelVersions()
    await appApi.updateServiceConfig(app.value.id, servicePlatform.value, 'PUSH', toPushConfigRequest())
    ElMessage.success('推送配置已保存')
    await loadData()
  } catch {
    ElMessage.error('保存失败')
  } finally {
    saving.value = false
  }
}

function toPushConfigRequest(): Record<string, unknown> {
  return {
    huaweiAppId: pushConfig.huawei.appId ?? '',
    huaweiAppSecret: pushConfig.huawei.appSecret ?? '',
    xiaomiAppId: pushConfig.xiaomi.appId ?? '',
    xiaomiAppKey: pushConfig.xiaomi.appKey ?? '',
    xiaomiAppSecret: pushConfig.xiaomi.appSecret ?? '',
    oppoAppId: pushConfig.oppo.appId ?? '',
    oppoAppKey: pushConfig.oppo.appKey ?? '',
    oppoMasterSecret: pushConfig.oppo.masterSecret ?? '',
    vivoAppId: pushConfig.vivo.appId ?? '',
    vivoAppKey: pushConfig.vivo.appKey ?? '',
    vivoAppSecret: pushConfig.vivo.appSecret ?? '',
    honorAppId: pushConfig.honor.appId ?? '',
    honorClientId: pushConfig.honor.clientId ?? '',
    honorClientSecret: pushConfig.honor.clientSecret ?? '',
    harmonyAppId: pushConfig.harmony.appId ?? '',
    harmonyAppSecret: pushConfig.harmony.appSecret ?? '',
    apnsTeamId: pushConfig.apns.teamId ?? '',
    apnsKeyId: pushConfig.apns.keyId ?? '',
    apnsBundleId: pushConfig.apns.bundleId ?? '',
    apnsKeyPath: pushConfig.apns.keyPath ?? '',
    apnsSandbox: pushConfig.apns.sandbox ?? false,
    fcmServiceAccountJson: pushConfig.fcm.serviceAccountJson ?? '',
    channels: pushConfig.channels,
    routing: pushConfig.routing,
  }
}

function defaultChannels(): PushNotificationChannelConfig[] {
  return [
    {
      key: 'im_message',
      channelId: 'xuqm_im_message',
      version: 1,
      name: '聊天消息',
      description: '单聊、群聊和好友消息',
      importance: 'HIGH',
      sound: true,
      vibration: true,
      badge: true,
    },
    {
      key: 'system_notice',
      channelId: 'xuqm_system_notice',
      version: 1,
      name: '系统通知',
      description: '系统通知和业务提醒',
      importance: 'DEFAULT',
      sound: true,
      vibration: true,
      badge: true,
    },
  ]
}

function defaultRouting(): Record<string, PushNotificationRouteConfig> {
  return {
    IM_MESSAGE: { channel: 'im_message', category: 'MESSAGE', priority: 'HIGH' },
    FRIEND_REQUEST: { channel: 'im_message', category: 'SOCIAL', priority: 'HIGH' },
    SYSTEM_NOTICE: { channel: 'system_notice', category: 'SYSTEM', priority: 'DEFAULT' },
  }
}

function normalizeChannels(channels?: PushNotificationChannelConfig[]): PushNotificationChannelConfig[] {
  const source = Array.isArray(channels) && channels.length > 0 ? channels : defaultChannels()
  return source.map((channel, index) => ({
    key: channel.key || `channel_${index + 1}`,
    channelId: channel.channelId || `xuqm_channel_${index + 1}`,
    version: Math.max(Number(channel.version || 1), 1),
    name: channel.name || channel.key || `通知通道 ${index + 1}`,
    description: channel.description ?? '',
    importance: channel.importance || 'DEFAULT',
    sound: channel.sound ?? true,
    vibration: channel.vibration ?? true,
    badge: channel.badge ?? true,
  }))
}

function normalizeRouting(routing?: Record<string, PushNotificationRouteConfig>): Record<string, PushNotificationRouteConfig> {
  return { ...defaultRouting(), ...(routing ?? {}) }
}

function ensureRoute(
  type: string,
  channel: string,
  category: string,
  priority: PushNotificationRouteConfig['priority'],
): PushNotificationRouteConfig {
  const route = { channel, category, priority }
  pushConfig.routing[type] = route
  return route
}

function addChannel() {
  const next = pushConfig.channels.length + 1
  pushConfig.channels.push({
    key: `custom_${next}`,
    channelId: `xuqm_custom_${next}`,
    version: 1,
    name: `自定义通道 ${next}`,
    description: '',
    importance: 'DEFAULT',
    sound: true,
    vibration: true,
    badge: true,
  })
}

function removeChannel(index: number) {
  const [removed] = pushConfig.channels.splice(index, 1)
  if (!removed) return
  Object.values(pushConfig.routing).forEach(route => {
    if (route.channel === removed.key) {
      route.channel = pushConfig.channels[0]?.key ?? ''
    }
  })
}

function bumpChangedChannelVersions() {
  const originalByKey = new Map(originalChannels.value.map(channel => [channel.key, channel]))
  pushConfig.channels.forEach(channel => {
    const original = originalByKey.get(channel.key)
    if (!original) return
    const immutableChanged = original.importance !== channel.importance
      || original.sound !== channel.sound
      || original.vibration !== channel.vibration
      || original.badge !== channel.badge
    if (immutableChanged && channel.version <= original.version) {
      channel.version = original.version + 1
    }
  })
}

async function onTogglePushService(enable: boolean) {
  if (enable) {
    ElMessage.info('请通过服务开通流程启用推送服务')
    return
  }
  await ElMessageBox.confirm('确认关闭离线推送服务？', '关闭服务', {
    type: 'warning',
    confirmButtonText: '确认关闭',
    cancelButtonText: '取消',
  })
  if (!app.value) return
  await appApi.toggleService(app.value.id, servicePlatform.value, 'PUSH', false)
  ElMessage.success('已关闭')
  await loadData()
}

function reloadConfig() {
  return loadData()
}

function copy(text: string) {
  navigator.clipboard.writeText(text)
  ElMessage.success('已复制')
}

onMounted(loadData)
onMounted(() => window.addEventListener('resize', updateViewport))
onBeforeUnmount(() => window.removeEventListener('resize', updateViewport))
</script>

<style scoped>
.mono { font-family: monospace; font-size: 12px; }
.hint { font-size: 12px; color: #909399; }
.info-card :deep(.el-descriptions__body) {
  overflow-x: auto;
}
.push-switch-row {
  margin-top: 12px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}
.vendor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 16px;
}
.vendor-card {
  min-height: 100%;
}
.vendor-hint {
  margin-bottom: 12px;
  font-size: 12px;
  color: #909399;
  line-height: 1.5;
}
.toolbar {
  margin-top: 16px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

@media (max-width: 767px) {
  .vendor-grid {
    grid-template-columns: 1fr;
  }

  .push-switch-row {
    flex-direction: column;
    align-items: flex-start;
  }

  .toolbar :deep(.el-button) {
    width: 100%;
  }

  .vendor-card :deep(.el-form-item__label) {
    padding-bottom: 4px;
  }
}
</style>
