<script setup lang="ts">
import { NCheckbox, NSelect, type SelectGroupOption } from 'naive-ui'
import { computed, ref, watch } from 'vue'

import { listBootVolumes } from '@/api/bootVolumes'
import { attachVolume, listVolumes } from '@/api/instances'
import FormField from '@/components/FormField.vue'
import FormModal from '@/components/FormModal.vue'
import { useAsync } from '@/composables/useAsync'
import { useToast } from '@/composables/useToast'

const props = defineProps<{
  show: boolean
  cfgId: number
  instanceId: string
  region?: string
  availabilityDomain: string
  attachedVolumeIds: string[]
}>()

const emit = defineEmits<{ 'update:show': [boolean]; attached: [] }>()

const message = useToast()
const submitting = ref(false)
const volumeId = ref<string | null>(null)
const readOnly = ref(false)

const volumes = useAsync(
  () => listVolumes(props.cfgId, props.availabilityDomain, undefined, props.region),
  false,
)
/** 未挂载的引导卷可作为数据卷附加（OCI attachVolume 直接接受引导卷 OCID） */
const bootVolumes = useAsync(
  () =>
    listBootVolumes(props.cfgId, props.availabilityDomain, undefined, props.region).catch(() => []),
  false,
)

watch(
  () => props.show,
  (v) => {
    if (v) {
      volumeId.value = null
      readOnly.value = false
      void volumes.run()
      void bootVolumes.run()
    }
  },
)

const options = computed<SelectGroupOption[]>(() => {
  const vols = (volumes.data.value ?? [])
    .filter((v) => v.lifecycleState === 'AVAILABLE' && !props.attachedVolumeIds.includes(v.id))
    .map((v) => ({ label: `${v.displayName}（${v.sizeInGBs} GB）`, value: v.id }))
  const bvs = (bootVolumes.data.value ?? [])
    .filter(
      (b) =>
        b.lifecycleState === 'AVAILABLE' &&
        !b.attachedInstanceId &&
        !props.attachedVolumeIds.includes(b.id),
    )
    .map((b) => ({ label: `${b.displayName}（${b.sizeInGBs} GB）`, value: b.id }))
  const groups: SelectGroupOption[] = []
  if (vols.length) groups.push({ type: 'group', label: '块卷', key: 'vol', children: vols })
  if (bvs.length) groups.push({ type: 'group', label: '引导卷（作数据卷）', key: 'bv', children: bvs })
  return groups
})

const loading = computed(() => volumes.loading.value || bootVolumes.loading.value)

async function submit() {
  if (!volumeId.value) return
  submitting.value = true
  try {
    await attachVolume(props.cfgId, props.instanceId, volumeId.value, readOnly.value, props.region)
    message.success('附加请求已提交，稍候在 OS 内可见新磁盘')
    emit('update:show', false)
    emit('attached')
  } catch (e) {
    message.error(e instanceof Error ? e.message : '附加失败')
  } finally {
    submitting.value = false
  }
}
</script>

<template>
  <FormModal
    :show="show"
    title="附加块卷"
    :submitting="submitting"
    :submit-disabled="!volumeId"
    submit-text="附加"
    @update:show="emit('update:show', $event)"
    @submit="submit"
  >
    <FormField
      label="块卷 / 引导卷"
      required
      hint="同可用域的块卷，或未挂载的引导卷（作为数据卷附加）"
      :error="!loading && !options.length ? '同可用域内没有可附加的块卷或引导卷' : undefined"
    >
      <NSelect
        v-model:value="volumeId"
        :options="options"
        :loading="loading"
        placeholder="选择块卷或引导卷"
      />
    </FormField>
    <NCheckbox v-model:checked="readOnly">只读附加</NCheckbox>
    <div class="mt-2 text-xs leading-relaxed text-ink-3">
      半虚拟化附加，运行中实例可热插拔；附加后仍需在实例 OS 内分区挂载文件系统。
    </div>
  </FormModal>
</template>
