<script setup lang="ts">
import { NButton, NDataTable, NInput, NInputGroup, NInputGroupLabel, NPopconfirm, NPopover, NSelect, NTooltip, type DataTableColumns } from 'naive-ui'
import { computed, h, reactive, ref, watch, type VNodeChild } from 'vue'
import { RouterLink, useRouter } from 'vue-router'

import { listAiChannels } from '@/api/aigateway'
import { deleteConfig, listConfigs, verifyConfig } from '@/api/configs'
import { listTasks } from '@/api/tasks'
import AccountTypeBadge from '@/components/AccountTypeBadge.vue'
import EditConfigModal from '@/components/config/EditConfigModal.vue'
import ImportConfigModal from '@/components/config/ImportConfigModal.vue'
import StatusBadge from '@/components/StatusBadge.vue'
import { parseSnatch, scopeCfgIds, STATUS_META, TYPE_LABEL } from '@/components/task/taskDisplay'
import { aliveMeta } from '@/composables/useAliveStatus'
import { fmtRelative, fmtTime } from '@/composables/useFormat'
import { useRegionAlias } from '@/composables/useRegionAlias'
import { useAsync } from '@/composables/useAsync'
import { useScopeStore } from '@/stores/scope'
import type { AccountType, OciConfigSummary, Task } from '@/types/api'
import { useToast } from '@/composables/useToast'

const message = useToast()
const router = useRouter()
const { alias: regionAlias } = useRegionAlias()
const scope = useScopeStore()

/** 租户增删改 / 测活后本页列表与全局作用域选择器一起刷新 */
function reloadConfigs() {
  void configs.run()
  void scope.refreshConfigs()
}
const keyword = ref('')
const UNGROUPED = '__ungrouped__'
const groupFilter = ref<string | null>(null)
const verifying = ref<number | null>(null)
const showImport = ref(false)
const showEdit = ref(false)
const editing = ref<OciConfigSummary | null>(null)

const configs = useAsync(listConfigs)
const tasks = useAsync(listTasks)
/** AI 探测任务的作用面 = 号池渠道对应租户 */
const aiChannels = useAsync(listAiChannels)

const groupOptions = computed(() => {
  const list = configs.data.value ?? []
  const names = [...new Set(list.map((c) => c.group).filter(Boolean))].sort()
  const options = names.map((g) => ({ label: g, value: g }))
  if (list.some((c) => !c.group)) options.push({ label: '未分组', value: UNGROUPED })
  return options
})

const filtered = computed(() => {
  const kw = keyword.value.trim().toLowerCase()
  let list = configs.data.value ?? []
  const g = groupFilter.value
  if (g !== null) list = list.filter((c) => (g === UNGROUPED ? !c.group : c.group === g))
  if (!kw) return list
  return list.filter((c) =>
    [c.alias, c.tenancyName, c.region, c.tenancyOcid, c.group].some((v) =>
      v.toLowerCase().includes(kw),
    ),
  )
})

/** 客户端分页:字面量对象会在重渲染时被重建导致状态丢失,须用 reactive 受控 */
const pagination = reactive({
  page: 1,
  pageSize: 10,
  showSizePicker: true,
  pageSizes: [10, 20, 50, 100],
  onUpdatePage: (p: number) => {
    pagination.page = p
  },
  onUpdatePageSize: (ps: number) => {
    pagination.pageSize = ps
    pagination.page = 1
  },
})
/** 搜索或分组过滤变化后回第 1 页,避免停留在越界页码 */
watch([keyword, groupFilter], () => {
  pagination.page = 1
})

/** 任务是否作用于该租户:抢机看目标租户;AI 探测看号池渠道(仅入池租户);
 *  测活 / 成本看范围(空 = 全部租户) */
function taskTouchesCfg(task: Task, cfgId: number): boolean {
  const s = parseSnatch(task)
  if (s) return s.cfgId === cfgId
  if (task.type === 'ai_probe')
    return (aiChannels.data.value ?? []).some((ch) => ch.ociConfigId === cfgId)
  const ids = scopeCfgIds(task)
  return !ids.length || ids.includes(cfgId)
}

function tasksFor(cfgId: number): Task[] {
  return (tasks.data.value ?? []).filter((t) => taskTouchesCfg(t, cfgId))
}

async function verify(row: OciConfigSummary) {
  verifying.value = row.id
  try {
    const result = await verifyConfig(row.id)
    const changed = Object.keys(result.changes).length
    message.success(changed ? `测活完成，${changed} 个字段有变更` : '测活完成，无变更')
    reloadConfigs()
  } catch (e) {
    message.error(e instanceof Error ? e.message : '测活失败')
  } finally {
    verifying.value = null
  }
}

function edit(row: OciConfigSummary) {
  editing.value = row
  showEdit.value = true
}

/** 把该租户与其主区域写入全局作用域选择器（顶栏立即生效） */
function setGlobal(row: OciConfigSummary) {
  scope.setGlobalScope(row.id, row.region)
  message.success(`全局已切换到「${row.alias}」· ${regionAlias(row.region)}`)
}

async function remove(row: OciConfigSummary) {
  try {
    await deleteConfig(row.id)
    message.success(`已删除「${row.alias}」及关联本地数据，OCI 云端资源未受影响`)
    reloadConfigs()
  } catch (e) {
    message.error(e instanceof Error ? e.message : '删除失败')
  }
}

function renderTenant(row: OciConfigSummary): VNodeChild {
  return h('div', { class: 'min-w-0' }, [
    h(
      RouterLink,
      {
        class: 'font-medium text-ink hover:text-accent',
        to: { name: 'tenant-detail', params: { id: row.id } },
      },
      { default: () => row.alias },
    ),
    h('div', { class: 'mono text-xs text-ink-3 mt-px' }, row.tenancyName),
  ])
}

/** 状态列：仅徽标；失联/暂停且有错误详情时 hover 徽标以 tooltip 展示完整 lastError */
function renderStatus(row: OciConfigSummary): VNodeChild {
  const meta = aliveMeta(row.aliveStatus)
  const badge = h(StatusBadge, { kind: meta.kind, label: meta.label })
  if (!['dead', 'suspended'].includes(row.aliveStatus) || !row.lastError) return badge
  return h(
    NTooltip,
    { trigger: 'hover', placement: 'top-start' },
    {
      trigger: () => badge,
      default: () => h('div', { class: 'max-w-80 text-xs' }, row.lastError),
    },
  )
}

/** 「后台任务」列：数量 + 悬停任务清单（点击任务名进详情） */
function renderTasks(row: OciConfigSummary): VNodeChild {
  const list = tasksFor(row.id)
  if (!list.length) return h('span', { class: 'text-[13px] text-ink-3' }, '—')
  return h(
    NPopover,
    { trigger: 'hover', placement: 'bottom-start' },
    {
      trigger: () =>
        h(
          'span',
          {
            class:
              'mono cursor-pointer border-b border-dashed border-ink-3/60 text-[13px] font-medium hover:text-accent',
            onClick: () => router.push({ name: 'tasks' }),
          },
          String(list.length),
        ),
      default: () => renderTaskPopover(list),
    },
  )
}

function renderTaskPopover(list: Task[]): VNodeChild {
  return h('div', { class: 'flex min-w-52 flex-col gap-1.5' }, [
    h('div', { class: 'text-xs text-ink-3' }, '关联后台任务 · 点击查看详情'),
    ...list.map((t) =>
      h('div', { class: 'flex items-center justify-between gap-4' }, [
        h(
          'button',
          {
            class: 'cursor-pointer text-left text-[13px] text-ink hover:text-accent',
            onClick: () => router.push({ name: 'task-detail', params: { taskId: t.id } }),
          },
          `${TYPE_LABEL[t.type]} · ${t.name}`,
        ),
        h(StatusBadge, { kind: STATUS_META[t.status].kind, label: STATUS_META[t.status].label }),
      ]),
    ),
  ])
}

/** 代理列:标签示关联态,hover 显示代理名 */
function renderProxy(row: OciConfigSummary): VNodeChild {
  if (!row.proxyId) return h('span', { class: 'text-[13px] text-ink-3' }, '直连')
  return h(
    NTooltip,
    { trigger: 'hover' },
    {
      trigger: () => h(StatusBadge, { kind: 'run', label: '代理', dot: false }),
      default: () => row.proxyName || `#${row.proxyId}`,
    },
  )
}

function renderActions(row: OciConfigSummary): VNodeChild {
  return h('div', { class: 'flex items-center gap-1' }, [
    h(
      NButton,
      {
        size: 'tiny',
        quaternary: true,
        disabled: scope.cfgId === row.id && scope.region === row.region,
        onClick: () => setGlobal(row),
      },
      { default: () => '设为全局' },
    ),
    h(
      NButton,
      { size: 'tiny', quaternary: true, loading: verifying.value === row.id, onClick: () => verify(row) },
      { default: () => '测活' },
    ),
    h(NButton, { size: 'tiny', quaternary: true, onClick: () => edit(row) }, { default: () => '修改' }),
    h(
      NPopconfirm,
      { onPositiveClick: () => remove(row), negativeText: '取消', positiveText: '删除' },
      {
        trigger: () =>
          h(NButton, { size: 'tiny', quaternary: true, type: 'error' }, { default: () => '删除' }),
        default: () =>
          h('div', { class: 'max-w-80 text-[13px] leading-relaxed' }, [
            h('div', { class: 'font-medium' }, `删除「${row.alias}」？`),
            h(
              'div',
              { class: 'mt-1 text-xs text-ink-3' },
              '将清理面板内关联数据：后台任务、测活 / 成本快照、回传事件、Webhook 密钥与 AI 渠道。',
            ),
            h(
              'div',
              { class: 'mt-0.5 text-xs text-ink-3' },
              'OCI 云端资源不受影响；云端日志回传链路请先在「其他」页销毁。',
            ),
          ]),
      },
    ),
  ])
}

const typeOrder: Record<AccountType, number> = { paid: 0, trial: 1, free: 2, unknown: 3 }

const columns = computed<DataTableColumns<OciConfigSummary>>(() => [
  {
    title: '租户',
    key: 'alias',
    minWidth: 200,
    sorter: (a, b) => a.alias.localeCompare(b.alias, 'zh-CN'),
    render: renderTenant,
  },
  {
    title: '分组',
    key: 'group',
    width: 100,
    sorter: (a, b) => a.group.localeCompare(b.group, 'zh-CN'),
    render: (row) =>
      row.group
        ? h('span', { class: 'text-[13px]' }, row.group)
        : h('span', { class: 'text-[13px] text-ink-3' }, '—'),
  },
  {
    title: '主区域',
    key: 'region',
    width: 195,
    sorter: (a, b) => regionAlias(a.region).localeCompare(regionAlias(b.region), 'zh-CN'),
    render: (row) =>
      h('span', { class: 'text-[13px] whitespace-nowrap' }, regionAlias(row.region)),
  },
  {
    title: '类别',
    key: 'accountType',
    width: 90,
    sorter: (a, b) => typeOrder[a.accountType] - typeOrder[b.accountType],
    render: (row) => h(AccountTypeBadge, { type: row.accountType }),
  },
  { title: '状态', key: 'aliveStatus', width: 120, render: renderStatus },
  { title: '代理', key: 'proxyId', width: 80, render: renderProxy },
  { title: '后台任务', key: 'tasks', width: 90, render: renderTasks },
  {
    title: '导入时间',
    key: 'createdAt',
    width: 110,
    sorter: (a, b) => a.createdAt.localeCompare(b.createdAt),
    render: (row) => h('span', { class: 'text-[13px] text-ink-2' }, fmtTime(row.createdAt).slice(0, 10)),
  },
  {
    title: '上次测活',
    key: 'lastVerifiedAt',
    width: 110,
    sorter: (a, b) => (a.lastVerifiedAt ?? '').localeCompare(b.lastVerifiedAt ?? ''),
    render: (row) => h('span', { class: 'text-[13px] text-ink-2' }, fmtRelative(row.lastVerifiedAt)),
  },
  { title: '操作', key: 'actions', width: 226, render: renderActions },
])
</script>

<template>
  <div class="flex flex-col gap-4 p-6 pb-8 max-md:p-3">
    <div class="flex flex-wrap items-center justify-between gap-2">
      <div class="flex flex-wrap items-baseline gap-2.5">
        <h1 class="page-title">租户</h1>
        <span class="text-[13px] text-ink-3">{{ configs.data.value?.length ?? '…' }} 个租户</span>
      </div>
      <NButton size="small" type="primary" @click="showImport = true">导入租户</NButton>
    </div>

    <div class="panel">
      <div class="flex flex-wrap items-center gap-2.5 px-4.5 py-3.5">
        <NInputGroup class="!w-56 max-md:!w-full">
          <NInputGroupLabel size="small">分组</NInputGroupLabel>
          <NSelect
            v-model:value="groupFilter"
            size="small"
            clearable
            placeholder="全部"
            :options="groupOptions"
            :disabled="!groupOptions.length"
          />
        </NInputGroup>
        <div class="max-w-72 min-w-40 flex-1 max-md:max-w-full">
          <NInput
            v-model:value="keyword"
            size="small"
            placeholder="搜索别名 / 租户名 / OCID / 分组"
            clearable
          />
        </div>
      </div>
      <NDataTable
        :columns="columns"
        :data="filtered"
        :loading="configs.loading.value"
        :pagination="pagination"
        :scroll-x="1200"
        :row-key="(r: OciConfigSummary) => r.id"
      />
    </div>

    <ImportConfigModal v-model:show="showImport" @imported="reloadConfigs()" />
    <EditConfigModal v-model:show="showEdit" :config="editing" @updated="reloadConfigs()" />
  </div>
</template>
