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

import { attachVnic } from '@/api/instances'
import { listSubnets } from '@/api/networks'
import FormField from '@/components/FormField.vue'
import FormModal from '@/components/FormModal.vue'
import ToggleCard from '@/components/ToggleCard.vue'
import { useAsync } from '@/composables/useAsync'
import { shortAd } from '@/composables/useFormat'
import { useToast } from '@/composables/useToast'

const props = defineProps<{
  show: boolean
  cfgId: number
  instanceId: string
  region?: string
  /** 已附加网卡数，仅用于配额提示文案 */
  attachedCount: number
}>()

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

const message = useToast()
const submitting = ref(false)
const subnetId = ref<string | null>(null)
const displayName = ref('')
const privateIp = ref('')
const assignPublicIp = ref(false)
const assignIpv6 = ref(false)

/** vcnId 传空列全部子网：次要网卡允许跨 VCN */
const subnets = useAsync(() => listSubnets(props.cfgId, '', props.region), false)

watch(
  () => props.show,
  (v) => {
    if (v) {
      subnetId.value = null
      displayName.value = ''
      privateIp.value = ''
      assignPublicIp.value = false
      assignIpv6.value = false
      void subnets.run()
    }
  },
)

const options = computed<SelectOption[]>(() =>
  (subnets.data.value ?? [])
    .filter((s) => s.lifecycleState === 'AVAILABLE')
    .map((s) => ({
      label: `${s.displayName}（${s.cidrBlock}）${s.availabilityDomain ? ` · ${shortAd(s.availabilityDomain)}` : ''}`,
      value: s.id,
    })),
)

const selected = computed(() => (subnets.data.value ?? []).find((s) => s.id === subnetId.value))
/** 私有子网禁分公网 IP；未启用 IPv6 的子网禁自动分配 */
const publicIpBlocked = computed(() => !!selected.value?.prohibitPublicIp)
const ipv6Blocked = computed(() => !!selected.value && !selected.value.ipv6CidrBlock)

watch(selected, (s) => {
  if (s?.prohibitPublicIp) assignPublicIp.value = false
  if (s && !s.ipv6CidrBlock) assignIpv6.value = false
})

async function submit() {
  if (!subnetId.value) return
  submitting.value = true
  try {
    await attachVnic(props.cfgId, props.instanceId, {
      region: props.region,
      subnetId: subnetId.value,
      displayName: displayName.value.trim(),
      privateIp: privateIp.value.trim(),
      assignPublicIp: assignPublicIp.value,
      assignIpv6: assignIpv6.value,
    })
    message.success('附加请求已提交，OS 内需自行配置新网卡 IP')
    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="附加 VNIC"
    :submitting="submitting"
    :submit-disabled="!subnetId"
    submit-text="附加"
    @update:show="emit('update:show', $event)"
    @submit="submit"
  >
    <FormField
      label="子网"
      required
      hint="与实例同 AD 的子网；跨 VCN 子网亦可选"
      :error="
        !subnets.loading.value && !options.length ? '该区域没有可用子网，请先创建' : undefined
      "
    >
      <NSelect
        v-model:value="subnetId"
        :options="options"
        :loading="subnets.loading.value"
        filterable
        placeholder="选择子网"
      />
    </FormField>
    <FormField label="显示名称">
      <NInput v-model:value="displayName" placeholder="留空自动生成" />
    </FormField>
    <FormField label="私网 IP">
      <NInput v-model:value="privateIp" placeholder="留空自动分配（推荐）" />
    </FormField>
    <div class="flex flex-col gap-2.5">
      <ToggleCard
        v-model="assignPublicIp"
        title="分配公网 IP"
        :desc="publicIpBlocked ? '所选子网为私有子网，不可分配公网 IP' : '仅公有子网可用；临时地址，分离即释放'"
        :disabled="publicIpBlocked"
      />
      <ToggleCard
        v-model="assignIpv6"
        title="自动分配 IPv6"
        :desc="
          ipv6Blocked
            ? '所选子网未启用 IPv6（可在 VCN 详情一键启用）'
            : '附加时同时分一个 IPv6；后续可在网卡列表继续添加'
        "
        :disabled="ipv6Blocked"
      />
    </div>
    <div class="mt-2 rounded-md bg-wash px-3 py-2 text-xs leading-relaxed text-ink-3">
      当前已附加 {{ attachedCount }} 张网卡。可附加数量由 shape 决定（如 A1.Flex 每 OCPU 1
      张），超出配额时 OCI 会拒绝请求。
    </div>
  </FormModal>
</template>
