<script setup lang="ts">
import { NDataTable, NModal, NPopover, type DataTableColumns } from 'naive-ui'
import { computed, h, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'

import { listConfigs } from '@/api/configs'
import { listLogEvents } from '@/api/logevents'
import DetailFieldList, { type DetailRow } from '@/components/DetailFieldList.vue'
import DetailHero, { type HeroChip } from '@/components/DetailHero.vue'
import JsonBlock from '@/components/JsonBlock.vue'
import StatusBadge from '@/components/StatusBadge.vue'
import TenantPicker from '@/components/TenantPicker.vue'
import { eventLabel, eventTail } from '@/composables/useEventLabel'
import { useAutoRefresh } from '@/composables/useAutoRefresh'
import { fmtTime } from '@/composables/useFormat'
import { useAsync } from '@/composables/useAsync'
import { useRegionAlias } from '@/composables/useRegionAlias'
import { useScopeStore } from '@/stores/scope'
import type { LogEvent, OciConfigSummary } from '@/types/api'
import { useToast } from '@/composables/useToast'

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

const rows = ref<LogEvent[]>([])
const loading = ref(false)
/** 租户筛选;null 为全部 */
const cfgFilter = ref<number | null>(null)

/** 租户摘要:hover 信息(别名/租户名/主区域)的数据源 */
const configs = useAsync(listConfigs)
const cfgById = computed(() => {
  const map = new Map<number, OciConfigSummary>()
  for (const c of configs.data.value ?? []) map.set(c.id, c)
  return map
})

const detail = ref<LogEvent | null>(null)
const showDetail = ref(false)

/** 受控远程分页:字面量对象会在重渲染时被重建导致状态丢失 */
const pagination = reactive({
  page: 1,
  pageSize: 20,
  itemCount: 0,
  showSizePicker: true,
  pageSizes: [20, 50, 100],
  onUpdatePage: (p: number) => {
    pagination.page = p
    void load()
  },
  onUpdatePageSize: (ps: number) => {
    pagination.pageSize = ps
    pagination.page = 1
    void load()
  },
})

async function load(silent = false) {
  if (!silent) loading.value = true
  try {
    const data = await listLogEvents({
      page: pagination.page,
      pageSize: pagination.pageSize,
      cfgId: cfgFilter.value ?? undefined,
    })
    rows.value = data.items
    pagination.itemCount = data.total
  } catch (e) {
    if (!silent) message.error(e instanceof Error ? e.message : '加载回传日志失败')
  } finally {
    if (!silent) loading.value = false
  }
}

function onFilter() {
  pagination.page = 1
  void load()
}

const aliasById = computed(() => {
  const map = new Map<number, string>()
  for (const o of scope.cfgOptions) map.set(Number(o.value), String(o.label))
  return map
})

/** 租户单元格:点击跳租户详情(阻止冒泡到行详情);hover 只展示值不加标签 */
function renderTenant(row: LogEvent) {
  const label = aliasById.value.get(row.ociConfigId) ?? `#${row.ociConfigId}`
  const cfg = cfgById.value.get(row.ociConfigId)
  const link = h(
    'span',
    {
      class: 'cursor-pointer border-b border-dashed border-ink-3/50 text-[13px] hover:text-accent',
      onClick: (e: MouseEvent) => {
        e.stopPropagation()
        void router.push({ name: 'tenant-detail', params: { id: row.ociConfigId } })
      },
    },
    label,
  )
  if (!cfg) return link
  return h(
    NPopover,
    { trigger: 'hover', placement: 'right' },
    {
      trigger: () => link,
      default: () =>
        h('div', { class: 'flex flex-col gap-1 text-xs' }, [
          h('div', { class: 'font-medium text-[13px]' }, cfg.alias),
          h('div', { class: 'mono text-ink-2' }, cfg.tenancyName),
          h('div', { class: 'text-ink-2' }, regionAlias(cfg.region)),
        ]),
    },
  )
}

/** 摘要头标题:事件中文名 → 类型尾段 → 解析状态兜底 */
const heroTitle = computed(() => {
  const d = detail.value
  if (!d) return ''
  if (d.eventType) return eventLabel(d.eventType) || eventTail(d.eventType)
  return d.processed ? '未识别事件' : '解析中…'
})

/** 摘要头 chips:接收时间 / 事件时间 / 来源 IP */
const heroChips = computed<HeroChip[]>(() => {
  const d = detail.value
  if (!d) return []
  return [
    { label: '接收', value: fmtTime(d.receivedAt) },
    { label: '事件时间', value: d.eventTime ? fmtTime(d.eventTime) : '—' },
    { label: '来源 IP', value: d.sourceIp || '—', mono: true },
  ]
})

/** 字段网格:头部未覆盖的补充字段;payload 原文由 JsonBlock 高亮展示 */
const detailRows = computed<DetailRow[]>(() => {
  const d = detail.value
  if (!d) return []
  return [
    { label: 'MessageId', value: d.messageId, mono: true, span: 2 as const, ellipsis: true },
    { label: '事件类型', value: d.eventType, mono: true, span: 2 as const, ellipsis: true },
  ]
})

function openDetail(row: LogEvent) {
  detail.value = row
  showDetail.value = true
}

const columns: DataTableColumns<LogEvent> = [
  {
    title: '接收时间',
    key: 'receivedAt',
    width: 150,
    render: (row) =>
      h('span', { class: 'text-[13px] whitespace-nowrap text-ink-2' }, fmtTime(row.receivedAt)),
  },
  {
    title: '租户',
    key: 'ociConfigId',
    width: 130,
    render: renderTenant,
  },
  {
    // 固定宽:常见事件类型约 45 字符,弹性空间让给来源列
    title: '事件类型',
    key: 'eventType',
    width: 400,
    ellipsis: { tooltip: true },
    render: (row) =>
      row.eventType
        ? h('span', { class: 'mono text-[12.5px]' }, row.eventType)
        : h('span', { class: 'text-[12.5px] text-ink-3' }, row.processed ? '未识别' : '解析中…'),
  },
  {
    title: 'IP',
    key: 'sourceIp',
    width: 140,
    render: (row) =>
      row.sourceIp
        ? h('span', { class: 'mono text-[12.5px] text-ink-2' }, row.sourceIp)
        : h('span', { class: 'text-[13px] text-ink-3' }, '—'),
  },
  {
    // 弹性列:实例名可较长,宽屏下尽量完整展示
    title: '来源',
    key: 'source',
    minWidth: 160,
    ellipsis: { tooltip: true },
    render: (row) => h('span', { class: 'text-[13px] text-ink-2' }, row.source || '—'),
  },
  {
    title: '标记',
    key: 'truncated',
    width: 90,
    render: (row) =>
      row.truncated ? h(StatusBadge, { kind: 'term', label: '已截断', dot: false }) : null,
  },
]

function rowProps(row: LogEvent) {
  return { style: 'cursor: pointer', onClick: () => openDetail(row) }
}

void load()
useAutoRefresh(() => load(true))
</script>

<template>
  <div class="panel">
    <div
      class="flex flex-wrap items-center justify-between gap-3 border-b border-line-soft px-4.5 py-3.5"
    >
      <div class="min-w-0">
        <div class="text-sm font-semibold">回传日志</div>
        <div class="mt-0.5 text-xs text-ink-3">
          OCI 侧推送的关键审计事件(Connector Hub → Notifications → 面板 webhook)
        </div>
      </div>
      <div class="flex flex-wrap items-center gap-2">
        <TenantPicker
          v-model:value="cfgFilter"
          size="small"
          clearable
          placeholder="全部租户"
          class="w-52"
          placement="bottom-end"
          :configs="scope.configs.data ?? []"
          :loading="scope.configs.loading"
          @update:value="onFilter"
        />
      </div>
    </div>
    <NDataTable
      remote
      :columns="columns"
      :data="rows"
      :loading="loading"
      :pagination="pagination"
      :scroll-x="880"
      :row-key="(r: LogEvent) => r.id"
      :row-props="rowProps"
    />
    <NModal v-model:show="showDetail" preset="card" closable :style="{ width: '720px', maxWidth: 'calc(100vw - 24px)' }">
      <template #header>
        <DetailHero
          v-if="detail"
          kind="回传日志 · Connector → Webhook"
          :title="heroTitle"
          :sub="`${aliasById.get(detail.ociConfigId) ?? `#${detail.ociConfigId}`} · ${detail.source || '来源未知'}`"
          :chips="heroChips"
        >
          <StatusBadge
            v-if="detail.eventType"
            kind="prov"
            :label="eventTail(detail.eventType)"
            :dot="false"
          />
        </DetailHero>
      </template>
      <div v-if="detail" class="flex flex-col gap-3.5">
        <DetailFieldList :rows="detailRows" :cols="2" />
        <JsonBlock
          :value="detail.payload"
          title="Payload 原文"
          :meta="`ONS 投递${detail.truncated ? ' · 超限已截断' : ''}`"
          max-height="42vh"
          wide
        />
      </div>
    </NModal>
  </div>
</template>
