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

import { createIdp, getIdentitySetting, type CreateIdpBody } from '@/api/tenant'
import FilePicker from '@/components/FilePicker.vue'
import FormField from '@/components/FormField.vue'
import FormModal from '@/components/FormModal.vue'
import { useToast } from '@/composables/useToast'

const props = defineProps<{ show: boolean; cfgId: number; domainId?: string }>()
const emit = defineEmits<{ 'update:show': [boolean]; created: [] }>()

const message = useToast()
const submitting = ref(false)
// 「用户需要提供主电子邮件地址」开启时 JIT 必须映射邮箱
const primaryEmailRequired = ref(false)

const nameIdFormatOptions = [
  { label: '无', value: 'saml-none' },
  { label: '电子邮件地址', value: 'saml-emailaddress' },
  { label: '持久标识符', value: 'saml-persistent' },
  { label: '临时标识符', value: 'saml-transient' },
  { label: '未指定', value: 'saml-unspecified' },
]
const idpAttrOptions = [
  { label: 'SAML 断言名称 ID（NameID）', value: 'nameid' },
  { label: '断言属性', value: 'attribute' },
]
const userAttrOptions = [
  { label: '用户名（userName）', value: 'userName' },
  { label: '主电子邮件（emails.primary.value）', value: 'emails.primary.value' },
]

// 默认值与控制台一致：名称 ID 格式「无」、NameID 映射用户名、
// JIT 开启建用户不更新、分配租户管理员组
const blank = {
  name: '',
  metadata: '',
  description: '',
  iconUrl: '',
  nameIdFormat: 'saml-none',
  idpUserAttr: 'nameid',
  assertionAttr: '',
  userStoreAttribute: 'userName',
  jitEnabled: true,
  jitCreate: true,
  jitUpdate: false,
  jitAssignAdminGroup: true,
  jitMapEmail: false,
}
const form = reactive({ ...blank })

watch(
  () => props.show,
  (v) => {
    if (!v) return
    Object.assign(form, blank)
    void loadIdentitySetting()
  },
)

async function loadIdentitySetting() {
  try {
    const s = await getIdentitySetting(props.cfgId)
    primaryEmailRequired.value = s.primaryEmailRequired
    if (s.primaryEmailRequired) form.jitMapEmail = true
  } catch {
    primaryEmailRequired.value = false
  }
}

// IDCS 只接受 http(s) 外链图标，data URI 会被拒（error.saml.identityprovider.invalidIconUrl）
const iconUrlValid = computed(() => {
  const v = form.iconUrl.trim()
  return !v || /^https?:\/\//.test(v)
})

const canSubmit = computed(
  () =>
    !!form.name.trim() &&
    form.metadata.includes('EntityDescriptor') &&
    iconUrlValid.value &&
    (form.idpUserAttr !== 'attribute' || !!form.assertionAttr.trim()),
)

function buildBody(): CreateIdpBody {
  return {
    name: form.name.trim(),
    metadata: form.metadata,
    description: form.description.trim() || undefined,
    iconUrl: form.iconUrl.trim() || undefined,
    nameIdFormat: form.nameIdFormat,
    assertionAttribute: form.idpUserAttr === 'attribute' ? form.assertionAttr.trim() : undefined,
    userStoreAttribute: form.userStoreAttribute,
    jitEnabled: form.jitEnabled,
    jitCreate: form.jitCreate,
    jitUpdate: form.jitUpdate,
    jitAssignAdminGroup: form.jitAssignAdminGroup,
    jitMapEmail: form.jitEnabled && form.jitMapEmail,
  }
}

async function submit() {
  submitting.value = true
  try {
    const created = await createIdp(props.cfgId, buildBody(), props.domainId)
    message.success(`IdP「${created.name}」已创建（禁用态），激活后显示到登录页`)
    emit('update:show', false)
    emit('created')
  } catch (e) {
    message.error(e instanceof Error ? e.message : '创建失败')
  } finally {
    submitting.value = false
  }
}
</script>

<template>
  <FormModal
    :show="show"
    title="创建 SAML IdP"
    :width="640"
    :submitting="submitting"
    :submit-disabled="!canSubmit"
    submit-text="创建（禁用态）"
    @update:show="emit('update:show', $event)"
    @submit="submit"
  >
    <FormField label="名称" required>
      <NInput v-model:value="form.name" placeholder="my-idp" />
    </FormField>
    <FormField
      label="IdP SAML metadata XML 文件"
      required
      hint="IdP 侧导出的 metadata XML；先在本页「下载 SP 元数据」导入 IdP 侧再创建"
      :error="
        form.metadata && !form.metadata.includes('EntityDescriptor')
          ? '文件内容不含 EntityDescriptor，请确认选择的是 SAML metadata XML'
          : undefined
      "
      :feedback="
        form.metadata.includes('EntityDescriptor')
          ? `已读取 ${(form.metadata.length / 1024).toFixed(1)} KB`
          : undefined
      "
    >
      <FilePicker
        :key="`md-${show}`"
        label="拖拽或点击上传 SAML metadata 文件"
        hint="支持 .xml，文件内容仅本地读取"
        accept=".xml"
        @load="(text) => (form.metadata = text)"
      />
    </FormField>
    <div class="grid grid-cols-2 gap-3 max-md:grid-cols-1">
      <FormField label="备注">
        <NInput v-model:value="form.description" placeholder="可选" />
      </FormField>
      <FormField
        label="Logo（登录页图标）"
        hint="展示在登录页 IdP 按钮上；身份域只接受 http(s) 外链图片 URL，不支持上传"
        :error="iconUrlValid ? undefined : '需为 http(s):// 开头的图片外链 URL'"
      >
        <div class="flex items-center gap-2">
          <img
            v-if="form.iconUrl && iconUrlValid"
            :src="form.iconUrl"
            alt=""
            class="h-7 w-7 flex-none rounded border border-line-soft object-contain"
          />
          <NInput v-model:value="form.iconUrl" placeholder="https://…/logo.png" />
        </div>
      </FormField>
    </div>

    <div class="mt-1 mb-2 border-t border-line-soft pt-3 text-[12.5px] font-semibold">
      映射用户身份
    </div>
    <FormField label="请求的名称 ID 格式" hint="向 IdP 请求断言时期望的 NameID 格式">
      <NSelect v-model:value="form.nameIdFormat" :options="nameIdFormatOptions" />
    </FormField>
    <div class="grid grid-cols-2 gap-3 max-md:grid-cols-1">
      <FormField label="IdP 用户属性" hint="从 SAML 断言中取哪个值来识别用户">
        <NSelect v-model:value="form.idpUserAttr" :options="idpAttrOptions" />
      </FormField>
      <FormField label="域用户属性" hint="用取到的值匹配身份域中用户的哪个属性">
        <NSelect v-model:value="form.userStoreAttribute" :options="userAttrOptions" />
      </FormField>
    </div>
    <FormField v-if="form.idpUserAttr === 'attribute'" label="断言属性名" required>
      <NInput v-model:value="form.assertionAttr" placeholder="如 mail、uid" />
    </FormField>

    <div class="mt-1 mb-2 flex items-center justify-between border-t border-line-soft pt-3">
      <span class="text-[12.5px] font-semibold">JIT 预配</span>
      <NSwitch v-model:value="form.jitEnabled" size="small" />
    </div>
    <div v-if="form.jitEnabled" class="mb-2 flex flex-col gap-1.5">
      <NCheckbox v-model:checked="form.jitCreate">首次联邦登录时自动创建用户</NCheckbox>
      <NCheckbox v-model:checked="form.jitUpdate">每次登录时按断言更新既有用户</NCheckbox>
      <NCheckbox v-model:checked="form.jitAssignAdminGroup">
        将 JIT 用户加入租户管理员组
      </NCheckbox>
      <NCheckbox
        v-model:checked="form.jitMapEmail"
        :disabled="primaryEmailRequired"
      >
        映射邮箱属性（断言 email → 主电子邮件）
        <span v-if="primaryEmailRequired" class="text-xs text-ink-3">
          — 域已开启「用户需要提供主电子邮件地址」，必须映射
        </span>
      </NCheckbox>
    </div>
    <div class="text-xs leading-relaxed text-ink-3">
      创建后为禁用态，需手动激活；映射与 JIT 均按上方配置写入身份域。
    </div>
  </FormModal>
</template>
