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

import { deleteBootVolume, listBootVolumes } from '@/api/bootVolumes'
import CompartmentSelect from '@/components/CompartmentSelect.vue'
import ConfirmPop from '@/components/ConfirmPop.vue'
import DeadPlaceholder from '@/components/DeadPlaceholder.vue'
import FootNote from '@/components/FootNote.vue'
import LifecycleBadge from '@/components/LifecycleBadge.vue'
import StatusBadge from '@/components/StatusBadge.vue'
import AttachBootVolumeModal from '@/components/storage/AttachBootVolumeModal.vue'
import EditBootVolumeModal from '@/components/storage/EditBootVolumeModal.vue'
import { fmtTime, shortAd, truncOcid, vpusLabel } from '@/composables/useFormat'
import { useAsync } from '@/composables/useAsync'
import { useScopeStore } from '@/stores/scope'
import type { BootVolume } from '@/types/api'
import { useToast } from '@/composables/useToast'

interface BvRow extends BootVolume {
  cfgId: number
}

/** 租户 / 区域 / 区间来自侧栏全局作用域 */
const scope = useScopeStore()
const message = useToast()

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

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

watch(
  [() => scope.currentConfig?.id, () => scope.region, () => scope.compartmentId],
  () => void rows.run(),
  { immediate: true },
)

/** 挂载 / 分离是异步动作，提交后延时补一次刷新 */
function refreshSoon() {
  void rows.run()
  setTimeout(() => void rows.run(), 6000)
}

const showEdit = ref(false)
const showAttach = ref(false)
const current = ref<BvRow | null>(null)

function openEdit(row: BvRow) {
  current.value = row
  showEdit.value = true
}

function openAttach(row: BvRow) {
  current.value = row
  showAttach.value = true
}

async function remove(row: BvRow) {
  try {
    await deleteBootVolume(row.cfgId, row.id, scope.region || undefined)
    message.success('引导卷已删除')
    void rows.run()
  } catch (e) {
    message.error(e instanceof Error ? e.message : '删除失败')
  }
}

async function copyImageOcid(row: BvRow) {
  await navigator.clipboard.writeText(row.imageId)
  message.success('已复制镜像 OCID')
}

function renderCopyIcon() {
  return h(
    'svg',
    { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', 'stroke-width': '1.5' },
    [
      h('rect', { x: '9', y: '9', width: '13', height: '13', rx: '2' }),
      h('path', { d: 'M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1' }),
    ],
  )
}

/** 名称行 + 来源镜像行（镜像名展示，按钮复制镜像 OCID） */
function renderName(row: BvRow) {
  const children = [h('div', { class: 'font-medium' }, row.displayName)]
  if (row.imageId)
    children.push(
      h('div', { class: 'mt-px flex min-w-0 items-center gap-0.5 text-xs text-ink-3' }, [
        h(
          'span',
          { class: 'truncate', title: row.imageName || row.imageId },
          row.imageName || truncOcid(row.imageId, 20),
        ),
        h(
          NButton,
          {
            size: 'tiny',
            quaternary: true,
            'aria-label': '复制镜像 OCID',
            onClick: () => copyImageOcid(row),
          },
          { icon: () => h(NIcon, { size: 13 }, { default: renderCopyIcon }) },
        ),
      ]),
    )
  return h('div', { class: 'min-w-0' }, children)
}

function renderActions(row: BvRow) {
  const attached = Boolean(row.attachedInstanceId)
  const gone = row.lifecycleState === 'TERMINATED' || row.lifecycleState === 'TERMINATING'
  const attachBtn = h(
    NButton,
    {
      size: 'tiny',
      quaternary: true,
      disabled: gone || attached || row.lifecycleState !== 'AVAILABLE',
      title: attached ? '已挂载到实例' : undefined,
      onClick: () => openAttach(row),
    },
    { default: () => '挂载' },
  )
  const deleteBtn =
    attached || gone
      ? h(
          NButton,
          { size: 'tiny', type: 'error', quaternary: true, disabled: true, title: attached ? '仅未挂载状态可删除' : undefined },
          { default: () => '删除' },
        )
      : h(
          ConfirmPop,
          {
            title: '删除该引导卷？',
            content: '数据不可恢复。',
            confirmText: '删除',
            onConfirm: () => remove(row),
          },
          {
            trigger: () =>
              h(NButton, { size: 'tiny', type: 'error', quaternary: true }, { default: () => '删除' }),
          },
        )
  return h('div', { class: 'flex items-center gap-1.5' }, [
    h(
      NButton,
      { size: 'tiny', quaternary: true, disabled: gone, onClick: () => openEdit(row) },
      { default: () => '编辑' },
    ),
    attachBtn,
    deleteBtn,
  ])
}

const columns = computed<DataTableColumns<BvRow>>(() => [
  { title: '引导卷', key: 'displayName', minWidth: 250, render: renderName },
  {
    title: 'AD',
    key: 'availabilityDomain',
    width: 80,
    render: (r) => h('span', { class: 'text-[13px]' }, shortAd(r.availabilityDomain)),
  },
  {
    title: '大小',
    key: 'sizeInGBs',
    width: 90,
    render: (r) => h('span', { class: 'tabular-nums' }, `${r.sizeInGBs} GB`),
  },
  {
    title: '性能',
    key: 'vpusPerGB',
    width: 120,
    render: (r) => h('span', { class: 'text-[13px]' }, vpusLabel(r.vpusPerGB)),
  },
  {
    title: '状态',
    key: 'lifecycleState',
    width: 116,
    render: (r) => h(LifecycleBadge, { state: r.lifecycleState }),
  },
  {
    title: '挂载状态',
    key: 'attached',
    width: 100,
    render: (r) =>
      h(StatusBadge, {
        kind: r.attachedInstanceId ? 'run' : 'check',
        label: r.attachedInstanceId ? '已挂载' : '未挂载',
      }),
  },
  {
    title: '挂载实例',
    key: 'attachedInstanceId',
    minWidth: 150,
    render: (r) =>
      r.attachedInstanceId
        ? h(
            RouterLink,
            {
              class: 'text-[13px] font-medium text-accent hover:text-accent-hover',
              to: {
                name: 'instance-detail',
                params: { cfgId: r.cfgId, instanceId: r.attachedInstanceId },
                query: { region: scope.region || undefined },
              },
            },
            {
              default: () =>
                r.attachedInstanceName || r.displayName.replace(' (Boot Volume)', ''),
            },
          )
        : h('span', { class: 'text-ink-3' }, '—'),
  },
  {
    title: '创建时间',
    key: 'timeCreated',
    width: 140,
    render: (r) => h('span', { class: 'text-[13px] text-ink-2' }, fmtTime(r.timeCreated)),
  },
  { title: '操作', key: 'actions', width: 190, 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-baseline justify-between gap-2">
      <h1 class="page-title">引导卷</h1>
      <span class="text-[13px] text-ink-3">
        {{ rows.data.value?.length ?? '…' }} 个 ·
        {{ scope.currentConfig?.alias ?? '…' }}
      </span>
    </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>
          <CompartmentSelect
            v-model:value="scope.compartmentId"
            :compartments="scope.compartments.data ?? []"
            :root-label="scope.rootLabel"
            :loading="scope.compartments.loading"
            :disabled="scope.compDisabled"
          />
        </NInputGroup>
      </div>
      <NDataTable
        :columns="columns"
        :data="rows.data.value ?? []"
        :loading="rows.loading.value"
        :scroll-x="1300"
        :row-key="(r: BvRow) => r.id"
      />
      <FootNote>
        挂载须实例同可用域且处于 STOPPED · 仅未挂载状态可删除
      </FootNote>
    </div>

    <EditBootVolumeModal
      v-model:show="showEdit"
      :cfg-id="current?.cfgId ?? null"
      :volume="current"
      :region="scope.region || undefined"
      @updated="rows.run()"
    />
    <AttachBootVolumeModal
      v-model:show="showAttach"
      :cfg-id="current?.cfgId ?? null"
      :volume="current"
      :region="scope.region || undefined"
      @attached="refreshSoon()"
    />
  </div>
</template>
