<template>
  <div class="page">
    <PageHeader
      :title="t('ingress.title')"
      :description="t('ingress.description')"
    >
      <template #actions>
        <el-button type="primary" @click="openCreate">{{ t('ingress.createKey') }}</el-button>
      </template>
    </PageHeader>

    <AppCard>
      <el-table :data="keys" v-loading="loading" size="small">
        <el-table-column prop="name" :label="t('common.name')" min-width="120" />
        <el-table-column prop="prefix" :label="t('ingress.keyPrefix')" width="140" />
        <el-table-column :label="t('ingress.protocol')" width="130">
          <template #default="{ row }">
            <el-tag :type="row.protocol === 'image' ? 'warning' : 'primary'" size="small">
              {{ row.protocol === 'image' ? t('ingress.protocolImage') : t('ingress.protocolText') }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="enabled" :label="t('common.status')" width="90">
          <template #default="{ row }">
            <el-tag :type="row.enabled ? 'success' : 'info'" size="small">{{ row.enabled ? t('common.enabled') : t('common.disabled') }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column :label="t('ingress.providerWhitelist')" min-width="140" show-overflow-tooltip>
          <template #default="{ row }">{{ formatWhitelist(row.allowed_providers_json) }}</template>
        </el-table-column>
        <el-table-column :label="t('ingress.modelWhitelist')" min-width="140" show-overflow-tooltip>
          <template #default="{ row }">{{ formatWhitelist(row.allowed_models_json) }}</template>
        </el-table-column>
        <el-table-column :label="t('common.budget')" min-width="140">
          <template #default="{ row }">
            {{ row.budget_used.toFixed(4) }} / {{ row.budget_limit || t('common.infinity') }}
          </template>
        </el-table-column>
        <el-table-column prop="request_count" :label="t('dashboard.requestCount')" width="90" />
        <el-table-column prop="token_count" :label="t('common.tokens')" width="100" />
        <el-table-column :label="t('common.actions')" width="320" fixed="right">
          <template #default="{ row }">
            <el-button size="small" link @click="openApiDoc(row)">{{ t('ingress.apiDoc') }}</el-button>
            <el-button size="small" link @click="openEdit(row)">{{ t('common.edit') }}</el-button>
            <el-button v-if="isTextKey(row)" size="small" link @click="openRouting(row)">{{ t('ingress.routingAction') }}</el-button>
            <el-button size="small" link @click="toggle(row)">{{ row.enabled ? t('common.disabled') : t('common.enabled') }}</el-button>
            <el-button size="small" type="danger" link @click="remove(row)">{{ t('common.delete') }}</el-button>
          </template>
        </el-table-column>
      </el-table>
    </AppCard>

    <el-dialog v-model="showCreate" :title="t('ingress.createDialogTitle')" width="560px" destroy-on-close @open="loadCatalog">
      <el-form label-width="120px">
        <el-form-item :label="t('common.name')"><el-input v-model="form.name" /></el-form-item>
        <el-form-item :label="t('ingress.protocol')">
          <el-radio-group v-model="form.protocol" @change="onProtocolChange">
            <el-radio value="text">{{ t('ingress.protocolText') }}</el-radio>
            <el-radio value="image">{{ t('ingress.protocolImage') }}</el-radio>
          </el-radio-group>
          <div class="form-hint">{{ t('ingress.protocolHint') }}</div>
        </el-form-item>
        <el-form-item :label="t('ingress.budgetLimit')"><el-input-number v-model="form.budget_limit" :min="0" :precision="4" class="w-full" /></el-form-item>
        <el-form-item :label="t('ingress.rpmLimit')"><el-input-number v-model="form.rate_limit_rpm" :min="0" class="w-full" /></el-form-item>
        <el-form-item :label="t('ingress.tpmLimit')"><el-input-number v-model="form.rate_limit_tpm" :min="0" class="w-full" /></el-form-item>
        <el-form-item :label="t('ingress.providerWhitelist')">
          <el-select
            :key="`create-providers-${form.protocol}`"
            v-model="form.allowed_providers"
            multiple
            filterable
            clearable
            collapse-tags
            collapse-tags-tooltip
            :placeholder="t('ingress.providerWhitelistPlaceholder')"
          >
            <el-option v-for="p in createProviderOptions" :key="p.name" :label="p.name" :value="p.name" />
          </el-select>
          <div class="form-hint">{{ t('ingress.whitelistHint') }}</div>
        </el-form-item>
        <el-form-item :label="t('ingress.modelWhitelist')">
          <el-select
            :key="`create-models-${form.protocol}-${form.allowed_providers.join(',')}`"
            v-model="form.allowed_models"
            multiple
            filterable
            clearable
            collapse-tags
            collapse-tags-tooltip
            :placeholder="t('ingress.modelWhitelistPlaceholder')"
          >
            <el-option
              v-for="m in createModelOptions"
              :key="m.model_id + '@' + m.provider_name"
              :label="m.label"
              :value="m.model_id"
            />
          </el-select>
          <div class="form-hint">{{ t('ingress.modelWhitelistHint') }}</div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showCreate = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" @click="create">{{ t('common.create') }}</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="showEdit" :title="t('ingress.editKeyTitle')" width="560px" destroy-on-close @open="loadCatalogForEdit">
      <el-form label-width="120px">
        <el-form-item :label="t('ingress.protocol')">
          <el-radio-group v-model="editForm.protocol" @change="onEditProtocolChange">
            <el-radio value="text">{{ t('ingress.protocolText') }}</el-radio>
            <el-radio value="image">{{ t('ingress.protocolImage') }}</el-radio>
          </el-radio-group>
          <div class="form-hint">{{ t('ingress.protocolHint') }}</div>
        </el-form-item>
        <el-form-item :label="t('ingress.providerWhitelist')">
          <el-select
            :key="`edit-providers-${editForm.protocol}`"
            v-model="editForm.allowed_providers"
            multiple
            filterable
            clearable
            collapse-tags
            collapse-tags-tooltip
            :placeholder="t('ingress.providerWhitelistPlaceholder')"
          >
            <el-option v-for="p in editProviderOptions" :key="p.name" :label="p.name" :value="p.name" />
          </el-select>
        </el-form-item>
        <el-form-item :label="t('ingress.modelWhitelist')">
          <el-select
            :key="`edit-models-${editForm.protocol}-${editForm.allowed_providers.join(',')}`"
            v-model="editForm.allowed_models"
            multiple
            filterable
            clearable
            collapse-tags
            collapse-tags-tooltip
            :placeholder="t('ingress.modelWhitelistPlaceholder')"
          >
            <el-option
              v-for="m in editModelOptions"
              :key="m.model_id + '@' + m.provider_name"
              :label="m.label"
              :value="m.model_id"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showEdit = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" @click="saveEdit">{{ t('common.save') }}</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="showPlainKey" :title="t('ingress.plainKeyTitle')" width="520px">
      <el-alert type="warning" :closable="false" :title="t('ingress.plainKeyWarning')" />
      <el-input v-model="plainKey" readonly class="u-mt-3">
        <template #append><el-button @click="copyKey">{{ t('common.copy') }}</el-button></template>
      </el-input>
    </el-dialog>

    <el-drawer v-model="routingVisible" :title="t('ingress.routingTitle', { name: current?.name || '' })" size="50%">
      <div class="drawer-toolbar">
        <el-button type="primary" size="small" @click="openRuleForm">{{ t('ingress.addRule') }}</el-button>
      </div>
      <el-table :data="routingRules" size="small">
        <el-table-column prop="model_pattern" :label="t('ingress.modelPattern')" min-width="140" />
        <el-table-column :label="t('ingress.providerId')" min-width="120">
          <template #default="{ row }">{{ providerName(row.provider_id) }}</template>
        </el-table-column>
        <el-table-column :label="t('ingress.keyIdOptional')" min-width="120">
          <template #default="{ row }">{{ keyName(row.provider_id, row.provider_key_id) }}</template>
        </el-table-column>
        <el-table-column prop="priority" :label="t('common.priority')" width="80" />
        <el-table-column prop="enabled" :label="t('common.enabled')" width="70">
          <template #default="{ row }"><el-tag :type="row.enabled ? 'success' : 'info'" size="small">{{ row.enabled ? t('common.yes') : t('common.no') }}</el-tag></template>
        </el-table-column>
        <el-table-column :label="t('common.actions')" width="80">
          <template #default="{ row }">
            <el-button size="small" type="danger" link @click="deleteRule(row)">{{ t('common.delete') }}</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-drawer>

    <el-dialog v-model="showRuleForm" :title="t('ingress.addRuleTitle')" width="480px" destroy-on-close @open="loadRoutingCatalog">
      <el-form label-width="120px">
        <el-form-item :label="t('ingress.modelPattern')">
          <el-input v-model="ruleForm.model_pattern" :placeholder="t('ingress.modelPatternPlaceholder')" />
        </el-form-item>
        <el-form-item :label="t('ingress.providerId')" required>
          <el-select
            v-model="ruleForm.provider_id"
            filterable
            class="w-full"
            :placeholder="t('ingress.providerIdPlaceholder')"
            @change="onRuleProviderChange"
          >
            <el-option v-for="p in routingProviders" :key="p.id" :label="p.name" :value="p.id" />
          </el-select>
        </el-form-item>
        <el-form-item :label="t('ingress.keyIdOptional')">
          <el-select
            v-model="ruleForm.provider_key_id"
            filterable
            clearable
            class="w-full"
            :placeholder="t('ingress.keyIdPlaceholder')"
            :disabled="!ruleForm.provider_id"
          >
            <el-option :label="t('common.auto')" :value="0" />
            <el-option
              v-for="k in keysForRuleProvider"
              :key="k.id"
              :label="k.name"
              :value="k.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item :label="t('common.priority')"><el-input-number v-model="ruleForm.priority" class="w-full" /></el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showRuleForm = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" @click="createRule">{{ t('common.add') }}</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import api, { type IngressKey, type Provider, type ProviderKey } from '@/api/client'
import PageHeader from '@/components/PageHeader.vue'
import AppCard from '@/components/AppCard.vue'

const { t } = useI18n()
const router = useRouter()

interface CatalogProvider { id: number; name: string; category: string }
interface RoutingProvider { id: number; name: string; keys: { id: number; name: string }[] }
interface ModelOption { model_id: string; display_name: string; provider_name: string; provider_category: string; label: string }

const keys = ref<IngressKey[]>([])
const loading = ref(false)
const showCreate = ref(false)
const showEdit = ref(false)
const showPlainKey = ref(false)
const plainKey = ref('')
const routingVisible = ref(false)
const showRuleForm = ref(false)
const current = ref<IngressKey | null>(null)
const routingRules = ref<any[]>([])
const ruleForm = ref({
  model_pattern: '',
  provider_id: undefined as number | undefined,
  provider_key_id: 0,
  priority: 10,
})
const routingProviders = ref<RoutingProvider[]>([])
const catalogProviders = ref<CatalogProvider[]>([])
const catalogModels = ref<ModelOption[]>([])
const form = ref({
  name: '',
  protocol: 'text' as 'text' | 'image',
  budget_limit: 0,
  rate_limit_rpm: 0,
  rate_limit_tpm: 0,
  allowed_providers: [] as string[],
  allowed_models: [] as string[],
})
const editForm = ref({
  protocol: 'text' as 'text' | 'image',
  allowed_providers: [] as string[],
  allowed_models: [] as string[],
})

const createProviderOptions = computed(() => catalogProvidersFor(form.value.protocol))
const editProviderOptions = computed(() => catalogProvidersFor(editForm.value.protocol))

const createModelOptions = computed(() =>
  filteredModelOptions(form.value.allowed_providers, form.value.protocol),
)
const editModelOptions = computed(() =>
  filteredModelOptions(editForm.value.allowed_providers, editForm.value.protocol),
)

watch(() => form.value.protocol, (protocol) => {
  const pruned = pruneWhitelistSelections(protocol, form.value.allowed_providers, form.value.allowed_models)
  form.value.allowed_providers = pruned.allowed_providers
  form.value.allowed_models = pruned.allowed_models
})

watch(() => editForm.value.protocol, (protocol) => {
  const pruned = pruneWhitelistSelections(protocol, editForm.value.allowed_providers, editForm.value.allowed_models)
  editForm.value.allowed_providers = pruned.allowed_providers
  editForm.value.allowed_models = pruned.allowed_models
})

watch(() => form.value.allowed_providers, (providers) => {
  const valid = new Set(filteredModelOptions(providers, form.value.protocol).map(m => m.model_id))
  form.value.allowed_models = form.value.allowed_models.filter(id => valid.has(id))
})

watch(() => editForm.value.allowed_providers, (providers) => {
  const valid = new Set(filteredModelOptions(providers, editForm.value.protocol).map(m => m.model_id))
  editForm.value.allowed_models = editForm.value.allowed_models.filter(id => valid.has(id))
})

const keysForRuleProvider = computed(() => {
  if (!ruleForm.value.provider_id) return []
  return routingProviders.value.find(p => p.id === ruleForm.value.provider_id)?.keys ?? []
})

function providerName(id: number) {
  return routingProviders.value.find(p => p.id === id)?.name ?? catalogProviders.value.find(p => p.id === id)?.name ?? `#${id}`
}

function keyName(providerId: number, keyId: number) {
  if (!keyId) return t('common.auto')
  const provider = routingProviders.value.find(p => p.id === providerId)
  return provider?.keys.find(k => k.id === keyId)?.name ?? `#${keyId}`
}

function onRuleProviderChange() {
  ruleForm.value.provider_key_id = 0
}

function parseJsonList(json: string): string[] {
  try {
    const v = JSON.parse(json || '[]')
    return Array.isArray(v) ? v : ['*']
  } catch {
    return ['*']
  }
}

function isAllowAll(list: string[]) {
  return list.length === 0 || list.includes('*')
}

function formatWhitelist(json: string) {
  const list = parseJsonList(json)
  if (isAllowAll(list)) return t('common.all')
  if (list.length <= 2) return list.join('、')
  return t('common.whitelistMore', { items: list.slice(0, 2).join('、'), count: list.length })
}

function jsonListToSelection(json: string): string[] {
  const list = parseJsonList(json)
  return isAllowAll(list) ? [] : list
}

function selectionToPayload(list: string[]) {
  return list.length === 0 ? [] : list
}

function isTextKey(row: IngressKey) {
  return (row.protocol || 'text') === 'text'
}

function providerMatchesProtocol(category: string, protocol: 'text' | 'image') {
  return protocol === 'image' ? category === 'image' : category !== 'image'
}

function catalogProvidersFor(protocol: 'text' | 'image') {
  return catalogProviders.value.filter(p => providerMatchesProtocol(p.category, protocol))
}

function pruneWhitelistSelections(
  protocol: 'text' | 'image',
  providers: string[],
  models: string[],
) {
  const validProviders = new Set(catalogProvidersFor(protocol).map(p => p.name))
  const nextProviders = providers.filter(name => validProviders.has(name))
  const validModels = new Set(filteredModelOptions(nextProviders, protocol).map(m => m.model_id))
  return {
    allowed_providers: nextProviders,
    allowed_models: models.filter(id => validModels.has(id)),
  }
}

function onProtocolChange() {
  const pruned = pruneWhitelistSelections(form.value.protocol, form.value.allowed_providers, form.value.allowed_models)
  form.value.allowed_providers = pruned.allowed_providers
  form.value.allowed_models = pruned.allowed_models
}

function onEditProtocolChange() {
  const pruned = pruneWhitelistSelections(editForm.value.protocol, editForm.value.allowed_providers, editForm.value.allowed_models)
  editForm.value.allowed_providers = pruned.allowed_providers
  editForm.value.allowed_models = pruned.allowed_models
}

function filteredModelOptions(selectedProviders: string[], protocol: 'text' | 'image' = 'text') {
  const models = catalogModels.value.filter(m => providerMatchesProtocol(m.provider_category, protocol))
  if (isAllowAll(selectedProviders)) return models
  return models.filter(m => selectedProviders.includes(m.provider_name))
}

async function loadCatalog() {
  const res = await api.get('/providers')
  const providers: Provider[] = res.data.data
  catalogProviders.value = providers.map(p => ({ id: p.id, name: p.name, category: p.category }))
  const models: ModelOption[] = []
  for (const p of providers) {
    for (const m of p.models || []) {
      if (!m.enabled) continue
      const ingressId = m.alias || m.model_id
      models.push({
        model_id: ingressId,
        display_name: m.display_name || ingressId,
        provider_name: p.name,
        provider_category: p.category,
        label: `${ingressId} (${p.name})`,
      })
    }
  }
  catalogModels.value = models
}

async function loadCatalogForEdit() {
  await loadCatalog()
}

async function loadRoutingCatalog() {
  const res = await api.get('/providers')
  const providers: Provider[] = (res.data.data ?? []).filter(p => p.category !== 'image')
  routingProviders.value = await Promise.all(providers.map(async (p) => {
    const keysRes = await api.get(`/providers/${p.id}/keys`)
    const keys = (keysRes.data.data as ProviderKey[] || [])
      .filter(k => k.enabled)
      .map(k => ({ id: k.id, name: k.name }))
    return { id: p.id, name: p.name, keys }
  }))
}

async function load() {
  loading.value = true
  try {
    const res = await api.get('/ingress-keys')
    keys.value = res.data.data
  } finally {
    loading.value = false
  }
}

function openCreate() {
  form.value = {
    name: '',
    protocol: 'text',
    budget_limit: 0,
    rate_limit_rpm: 0,
    rate_limit_tpm: 0,
    allowed_providers: [],
    allowed_models: [],
  }
  showCreate.value = true
}

async function create() {
  const res = await api.post('/ingress-keys', {
    name: form.value.name,
    protocol: form.value.protocol,
    budget_limit: form.value.budget_limit,
    rate_limit_rpm: form.value.rate_limit_rpm,
    rate_limit_tpm: form.value.rate_limit_tpm,
    allowed_providers: selectionToPayload(form.value.allowed_providers),
    allowed_models: selectionToPayload(form.value.allowed_models),
  })
  showCreate.value = false
  plainKey.value = res.data.plain_key
  showPlainKey.value = true
  load()
}

function openApiDoc(row: IngressKey) {
  const protocol = row.protocol === 'image' ? 'image' : 'text'
  router.push(protocol === 'image' ? '/ingress/docs/image' : '/ingress/docs/text')
}

function openEdit(row: IngressKey) {
  current.value = row
  editForm.value = {
    protocol: row.protocol || 'text',
    allowed_providers: jsonListToSelection(row.allowed_providers_json),
    allowed_models: jsonListToSelection(row.allowed_models_json),
  }
  showEdit.value = true
}

async function saveEdit() {
  if (!current.value) return
  await api.put(`/ingress-keys/${current.value.id}`, {
    protocol: editForm.value.protocol,
    allowed_providers: selectionToPayload(editForm.value.allowed_providers),
    allowed_models: selectionToPayload(editForm.value.allowed_models),
  })
  showEdit.value = false
  ElMessage.success(t('ingress.protocolUpdated'))
  load()
}

async function toggle(row: IngressKey) {
  await api.put(`/ingress-keys/${row.id}`, { enabled: !row.enabled })
  load()
}

async function remove(row: IngressKey) {
  await ElMessageBox.confirm(t('ingress.confirmDeleteKey'))
  await api.delete(`/ingress-keys/${row.id}`)
  ElMessage.success(t('providers.deleted'))
  load()
}

function copyKey() {
  navigator.clipboard.writeText(plainKey.value)
  ElMessage.success(t('ingress.copied'))
}

async function openRouting(row: IngressKey) {
  current.value = row
  await loadRoutingCatalog()
  const res = await api.get(`/ingress-keys/${row.id}/routing-rules`)
  routingRules.value = res.data.data
  routingVisible.value = true
}

function openRuleForm() {
  ruleForm.value = {
    model_pattern: '',
    provider_id: undefined,
    provider_key_id: 0,
    priority: 10,
  }
  showRuleForm.value = true
}

async function createRule() {
  if (!current.value) return
  if (!ruleForm.value.model_pattern.trim()) {
    ElMessage.warning(t('ingress.modelPatternPlaceholder'))
    return
  }
  if (!ruleForm.value.provider_id) {
    ElMessage.warning(t('ingress.providerRequired'))
    return
  }
  await api.post(`/ingress-keys/${current.value.id}/routing-rules`, {
    model_pattern: ruleForm.value.model_pattern.trim(),
    provider_id: ruleForm.value.provider_id,
    provider_key_id: ruleForm.value.provider_key_id || 0,
    priority: ruleForm.value.priority,
  })
  showRuleForm.value = false
  openRouting(current.value)
  ElMessage.success(t('ingress.ruleAdded'))
}

async function deleteRule(row: any) {
  await api.delete(`/routing-rules/${row.id}`)
  if (current.value) openRouting(current.value)
}

onMounted(() => {
  loadCatalog()
  load()
})
</script>
