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

import { instanceAction, listInstances } from '@/api/instances'
import DeadPlaceholder from '@/components/DeadPlaceholder.vue'
import CreateInstanceModal from '@/components/instance/CreateInstanceModal.vue'
import LifecycleBadge from '@/components/LifecycleBadge.vue'
import { useRegionAlias } from '@/composables/useRegionAlias'
import { shortAd } from '@/composables/useFormat'
import { useAsync } from '@/composables/useAsync'
import { INSTANCE_TRANSIENT_STATES, useTransientPoll } from '@/composables/useTransientPoll'
import { useScopeStore } from '@/stores/scope'
import type { Instance, PowerAction } from '@/types/api'
import { useToast } from '@/composables/useToast'

interface InstanceRow extends Instance {
  cfgId: number
  cfgAlias: string
}

const message = useToast()
const { alias } = useRegionAlias()

/** 租户 / 区域 / 区间来自侧栏全局作用域，页内只做区间切换与搜索 */
const scope = useScopeStore()

const keyword = ref('')
const showCreate = ref(false)

const rows = useAsync<InstanceRow[]>(async () => {
  const cfg = scope.currentConfig
  if (!cfg || cfg.aliveStatus === 'dead') return []
  const compartmentId = scope.compartmentId || undefined
  try {
    const list = await listInstances(cfg.id, scope.region || undefined, compartmentId)
    return list.map((item) => ({ ...item, cfgId: cfg.id, cfgAlias: cfg.alias }))
  } catch {
    return []
  }
}, false)

/** 当前作用域租户失联时整页替换占位,不发起资源请求 */
const isDead = computed(() => scope.currentConfig?.aliveStatus === 'dead')

// 同一 flush 内租户与区域先后变化只触发一次查询，避免旧区域请求覆盖新结果
watch(
  [() => scope.currentConfig?.id, () => scope.region, () => scope.compartmentId],
  () => void rows.run(),
  { immediate: true },
)

// 创建 / 电源操作后存在过渡态行时每 5 秒静默刷新（不闪 loading），直到全部进入稳态
useTransientPoll(
  () => rows.data.value,
  (list) => !!list?.some((r) => INSTANCE_TRANSIENT_STATES.includes(r.lifecycleState)),
  () => void rows.run({ silent: true }),
)

const filtered = computed(() => {
  const kw = keyword.value.trim().toLowerCase()
  return (rows.data.value ?? []).filter((r) => {
    if (!kw) return true
    return [r.displayName, r.id, r.publicIp, r.privateIp].some((v) =>
      v?.toLowerCase().includes(kw),
    )
  })
})

function isEnded(row: InstanceRow): boolean {
  return row.lifecycleState === 'TERMINATED' || row.lifecycleState === 'TERMINATING'
}

async function power(row: InstanceRow, action: PowerAction) {
  try {
    await instanceAction(row.cfgId, row.id, action, scope.region || undefined)
    message.success(`${action} 已提交：${row.displayName}`)
    void rows.run()
  } catch (e) {
    message.error(e instanceof Error ? e.message : '操作失败')
  }
}

const columns = computed<DataTableColumns<InstanceRow>>(() => [
  {
    title: '实例',
    key: 'displayName',
    minWidth: 180,
    render: (row) =>
      h('div', { class: 'min-w-0' }, [
        h(
          RouterLink,
          {
            class: 'font-medium text-ink hover:text-accent',
            to: {
              name: 'instance-detail',
              params: { cfgId: row.cfgId, instanceId: row.id },
              query: { region: scope.region || undefined },
            },
          },
          { default: () => row.displayName },
        ),
        h('div', { class: 'text-xs text-ink-3 mt-px' }, row.cfgAlias),
      ]),
  },
  {
    title: 'Shape',
    key: 'shape',
    minWidth: 190,
    render: (row) =>
      h('div', [
        h('div', { class: 'text-[13px]' }, row.shape),
        h('div', { class: 'text-xs text-ink-3 mt-px' }, `${row.ocpus} OCPU · ${row.memoryInGBs} GB`),
      ]),
  },
  {
    title: '区域 / AD',
    key: 'region',
    minWidth: 170,
    render: (row) =>
      h('div', [
        h('div', { class: 'text-[13px]' }, alias(row.region)),
        h('div', { class: 'text-xs text-ink-3 mt-px' }, shortAd(row.availabilityDomain)),
      ]),
  },
  {
    title: '公网 IP',
    key: 'publicIp',
    minWidth: 130,
    render: (row) => h('span', { class: 'mono' }, row.publicIp || '—'),
  },
  {
    title: '状态',
    key: 'lifecycleState',
    minWidth: 130,
    render: (row) => h(LifecycleBadge, { state: row.lifecycleState }),
  },
  {
    title: '操作',
    key: 'actions',
    width: 150,
    render: (row) =>
      h('div', { class: 'flex items-center gap-1' }, [
        row.lifecycleState === 'STOPPED'
          ? h(
              NButton,
              { size: 'tiny', quaternary: true, disabled: isEnded(row), onClick: () => power(row, 'START') },
              { default: () => '启动' },
            )
          : h(
              NButton,
              { size: 'tiny', quaternary: true, disabled: isEnded(row), onClick: () => power(row, 'STOP') },
              { default: () => '停止' },
            ),
        h(
          NButton,
          { size: 'tiny', quaternary: true, disabled: isEnded(row), onClick: () => power(row, 'RESET') },
          { default: () => '重启' },
        ),
      ]),
  },
])
</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 items-baseline gap-2.5">
        <h1 class="page-title">实例</h1>
        <span class="text-[13px] text-ink-3">
          {{ rows.data.value?.length ?? '…' }} 台 ·
          {{ scope.currentConfig?.alias ?? '…' }}
        </span>
      </div>
      <NButton v-if="!isDead" size="small" type="primary" @click="showCreate = true">
        创建实例
      </NButton>
    </div>

    <DeadPlaceholder v-if="isDead" :last-error="scope.currentConfig?.lastError" />
    <div v-else class="panel">
      <div class="flex flex-wrap items-center gap-2 px-4.5 py-3">
        <NInputGroup class="!w-72 max-md:!w-full">
          <NInputGroupLabel size="small">区间</NInputGroupLabel>
          <NSelect
            v-model:value="scope.compartmentId"
            :options="scope.compOptions"
            :loading="scope.compartments.loading"
            :disabled="scope.compDisabled"
            size="small"
          />
        </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 / IP"
            clearable
          />
        </div>
      </div>
      <NDataTable
        :columns="columns"
        :data="filtered"
        :loading="rows.loading.value"
        :pagination="{ pageSize: 10 }"
        :scroll-x="960"
        :row-key="(r: InstanceRow) => r.id"
      />
    </div>

    <CreateInstanceModal
      v-model:show="showCreate"
      :cfg-id="scope.currentConfig?.id ?? null"
      :compartment-id="scope.compartmentId"
      :region="scope.region"
      @created="rows.run()"
    />
  </div>
</template>
