<script setup lang="ts">
import {
  NCheckbox,
  NDataTable,
  NInput,
  NInputGroup,
  NInputGroupLabel,
  NSelect,
  type DataTableColumns,
} from 'naive-ui'
import { computed, h, reactive, ref, watch } from 'vue'

import { listCachedRegions } from '@/api/configs'
import { listLimitServices, listLimits } from '@/api/tenant'
import FootNote from '@/components/FootNote.vue'
import { regionCity, shortAd } from '@/composables/useFormat'
import { useAsync } from '@/composables/useAsync'
import type { LimitItem } from '@/types/api'

const props = defineProps<{ cfgId: number }>()

const service = ref('compute')
const name = ref('')
const region = ref('')
const scopeType = ref<'' | 'GLOBAL' | 'REGION' | 'AD'>('')
const withAvail = ref(false)
const hideZero = ref(false)

const scopeOptions = [
  { label: '全部作用域', value: '' },
  { label: 'GLOBAL', value: 'GLOBAL' },
  { label: 'REGION', value: 'REGION' },
  { label: 'AD', value: 'AD' },
]

const services = useAsync(() => listLimitServices(props.cfgId))
/** 区域选项来自服务端缓存（未开启多区域的租户只返回默认区域） */
const regions = useAsync(() => listCachedRegions(props.cfgId).catch(() => []))
const limits = useAsync(() =>
  listLimits(props.cfgId, {
    service: service.value,
    name: name.value,
    region: region.value || undefined,
    scopeType: scopeType.value || undefined,
    // 下推服务端过滤：0 配额不占「查用量」的 100 条并发名额
    nonZero: hideZero.value || undefined,
    withAvailability: withAvail.value,
  }),
)

// 区域列表加载后默认选中主区域；已选值失效（退订）时同样回退
watch(
  () => regions.data.value,
  (subs) => {
    if (!subs?.length) return
    if (!region.value || !subs.some((s) => s.name === region.value))
      region.value = subs.find((s) => s.isHomeRegion)?.name ?? subs[0].name
  },
)

/** 选项用括号内城市短名（与全局选择器一致），避免选中框被长名截断 */
const regionOptions = computed(() =>
  (regions.data.value ?? []).map((s) => ({
    label: s.isHomeRegion ? `${regionCity(s.alias)} · 主` : regionCity(s.alias),
    value: s.name,
  })),
)

watch([service, withAvail, region, scopeType, hideZero], () => void limits.run())

const rows = computed(() =>
  hideZero.value ? (limits.data.value ?? []).filter((r) => r.value !== 0) : (limits.data.value ?? []),
)

const serviceOptions = computed(
  () =>
    services.data.value?.map((s) => ({ label: s.description || s.name, value: s.name })) ?? [
      { label: 'Compute', value: 'compute' },
    ],
)

function usagePct(row: LimitItem): number | null {
  if (row.used === undefined || row.value === 0) return null
  return Math.round((row.used / row.value) * 100)
}

/** 受控分页：字面量对象会在重渲染时被重建导致页大小切换失效 */
const pagination = reactive({
  page: 1,
  pageSize: 10,
  showSizePicker: true,
  pageSizes: [10, 20, 50],
  onUpdatePage: (p: number) => {
    pagination.page = p
  },
  onUpdatePageSize: (ps: number) => {
    pagination.pageSize = ps
    pagination.page = 1
  },
})

const baseColumns: DataTableColumns<LimitItem> = [
  {
    title: '配额项',
    key: 'name',
    minWidth: 230,
    render: (row) =>
      h('div', [
        h('div', { class: 'mono text-[12.5px] text-ink' }, row.name),
        h(
          'div',
          { class: 'text-xs text-ink-3 mt-px' },
          row.availabilityDomain ? shortAd(row.availabilityDomain) : row.scopeType,
        ),
      ]),
  },
  {
    title: '上限',
    key: 'value',
    width: 130,
    render: (r) =>
      h(
        'span',
        { class: 'tabular-nums whitespace-nowrap' },
        r.value.toLocaleString('en-US'),
      ),
  },
]

const availColumns: DataTableColumns<LimitItem> = [
  {
    title: '已用',
    key: 'used',
    width: 80,
    render: (r) => h('span', { class: 'tabular-nums' }, r.used === undefined ? '—' : String(r.used)),
  },
  {
    title: '可用',
    key: 'available',
    width: 80,
    render: (r) =>
      h('span', { class: 'tabular-nums' }, r.available === undefined ? '—' : String(r.available)),
  },
  {
    title: '用量',
    key: 'pct',
    minWidth: 160,
    render: (row) => {
      const pct = usagePct(row)
      if (pct === null) return h('span', { class: 'text-xs text-ink-3' }, '无用量数据')
      const full = pct >= 100
      return h('div', { class: 'flex items-center gap-2' }, [
        h('div', { class: 'h-1.5 w-24 overflow-hidden rounded-full bg-line-soft' }, [
          h('div', {
            class: 'h-full rounded-full',
            style: { width: `${Math.min(pct, 100)}%`, background: full ? 'var(--color-err)' : 'var(--color-ok)' },
          }),
        ]),
        h(
          'span',
          {
            class: 'text-[12.5px] tabular-nums',
            style: full ? 'color:var(--color-err);font-weight:600' : 'color:var(--color-ink-2)',
          },
          `${pct}%`,
        ),
      ])
    },
  },
]

const columns = computed(() => (withAvail.value ? [...baseColumns, ...availColumns] : baseColumns))
</script>

<template>
  <div class="panel">
    <div class="flex flex-wrap items-center gap-2 px-4.5 py-3">
      <div class="text-sm font-semibold">服务配额</div>
      <div class="flex-1" />
      <NInputGroup class="!w-60 max-md:!w-full">
        <NInputGroupLabel size="small">区域</NInputGroupLabel>
        <NSelect
          v-model:value="region"
          size="small"
          filterable
          :options="regionOptions"
          :loading="regions.loading.value"
          :consistent-menu-width="false"
        />
      </NInputGroup>
      <NInputGroup class="!w-72 max-lg:!w-60 max-md:!w-full">
        <NInputGroupLabel size="small">服务</NInputGroupLabel>
        <NSelect
          v-model:value="service"
          size="small"
          filterable
          :options="serviceOptions"
          :loading="services.loading.value"
        />
      </NInputGroup>
      <NInputGroup class="!w-52 max-lg:!w-44 max-md:!w-full">
        <NInputGroupLabel size="small">作用域</NInputGroupLabel>
        <NSelect v-model:value="scopeType" size="small" :options="scopeOptions" />
      </NInputGroup>
      <NInputGroup class="!w-56 max-lg:!w-44 max-md:!w-full">
        <NInputGroupLabel size="small">配额名</NInputGroupLabel>
        <NInput
          v-model:value="name"
          size="small"
          placeholder="如 core-count"
          clearable
          @keyup.enter="limits.run()"
          @clear="limits.run()"
        />
      </NInputGroup>
      <NCheckbox v-model:checked="hideZero" size="small">忽略 0 配额</NCheckbox>
      <NCheckbox v-model:checked="withAvail" size="small">查用量</NCheckbox>
    </div>
    <NDataTable
      :columns="columns"
      :data="rows"
      :loading="limits.loading.value"
      :pagination="pagination"
      :scroll-x="withAvail ? 660 : 380"
      :row-key="(r: LimitItem) => r.name + (r.availabilityDomain ?? '')"
    />
    <FootNote>
      勾选「查用量」后单次限 100 条，超出请用配额名 / 作用域过滤收窄，配合「忽略 0
      配额」（服务端过滤）可大幅释放名额；不支持用量查询的配额自动跳过并显示「无用量数据」
    </FootNote>
  </div>
</template>
