<template>
  <ElDialog
    v-model="dialogVisible"
    :title="dialogTitle"
    width="520px"
    align-center
    :close-on-click-modal="false"
  >
    <ElForm ref="formRef" :model="formData" :rules="rules" label-width="96px">
      <ElFormItem v-if="showTenantField" :label="t('user.field.tenant')" prop="tenantId">
        <ElSelect
          v-model="formData.tenantId"
          filterable
          clearable
          :disabled="isEdit"
          :placeholder="t('user.placeholder.tenant')"
        >
          <ElOption
            v-for="option in tenantOptions"
            :key="option.value"
            :label="option.label"
            :value="option.value"
          />
        </ElSelect>
      </ElFormItem>
      <ElFormItem :label="t('user.field.account')" prop="account">
        <ElInput
          v-model="formData.account"
          :disabled="isEdit"
          :placeholder="t('user.placeholder.account')"
          maxlength="64"
        />
      </ElFormItem>
      <ElFormItem :label="t('user.field.displayName')" prop="displayName">
        <ElInput
          v-model="formData.displayName"
          :placeholder="t('user.placeholder.displayName')"
          maxlength="64"
        />
      </ElFormItem>
      <ElFormItem v-if="isAdd" :label="t('user.field.password')" prop="password">
        <ElInput
          v-model="formData.password"
          type="password"
          show-password
          :placeholder="t('user.placeholder.password')"
          maxlength="32"
        />
      </ElFormItem>
      <ElFormItem :label="t('user.field.phone')" prop="phone">
        <ElInput
          v-model="formData.phone"
          :placeholder="t('user.placeholder.phone')"
          maxlength="32"
        />
      </ElFormItem>
      <ElFormItem :label="t('user.field.email')" prop="email">
        <ElInput
          v-model="formData.email"
          :placeholder="t('user.placeholder.email')"
          maxlength="128"
        />
      </ElFormItem>
      <ElFormItem :label="t('user.field.avatar')" prop="avatar">
        <div class="flex items-center gap-3">
          <div
            class="relative h-[84px] w-[84px] overflow-hidden rounded-full border border-[var(--el-border-color)] bg-[var(--el-fill-color-light)]"
          >
            <ElImage
              v-if="formData.avatar"
              :src="formData.avatar"
              fit="cover"
              class="h-full w-full rounded-full"
              :preview-src-list="[formData.avatar]"
              preview-teleported
            />
            <div
              v-else
              class="flex h-full w-full items-center justify-center text-xs text-[var(--el-text-color-secondary)]"
            >
              {{ t('user.avatar.noImage') }}
            </div>
          </div>

          <div class="flex flex-1 flex-col gap-2">
            <div class="flex items-center gap-2">
              <ElButton :loading="avatarUploading" type="primary" plain @click="openAvatarDialog">
                {{ formData.avatar ? t('user.avatar.reupload') : t('user.avatar.upload') }}
              </ElButton>
              <ElButton
                v-if="formData.avatar"
                :disabled="avatarUploading"
                type="danger"
                plain
                @click="handleAvatarRemove"
              >
                {{ t('user.avatar.remove') }}
              </ElButton>
            </div>
            <div class="text-xs text-[var(--el-text-color-secondary)]">
              {{ avatarFileName || t('user.avatar.tip') }}
            </div>
          </div>

          <input
            ref="avatarInputRef"
            type="file"
            class="hidden"
            accept="image/*"
            @change="(e) => handleAvatarChange(e)"
          />
        </div>
      </ElFormItem>
      <ElFormItem :label="t('user.field.roles')" prop="roleIds">
        <ElSelect
          v-model="formData.roleIds"
          multiple
          filterable
          clearable
          collapse-tags
          :placeholder="t('user.placeholder.roles')"
        >
          <ElOption
            v-for="option in roleOptions"
            :key="option.value"
            :label="option.label"
            :value="option.value"
          />
        </ElSelect>
      </ElFormItem>
      <ElFormItem v-if="isAdd" :label="t('user.field.status')" prop="status">
        <ElSelect v-model="formData.status" :placeholder="t('user.placeholder.status')">
          <ElOption
            v-for="option in statusOptions"
            :key="option.value"
            :label="option.label"
            :value="option.value"
          />
        </ElSelect>
      </ElFormItem>
    </ElForm>
    <ImgCutter
      ref="avatarCutterRef"
      :is-modal="true"
      :show-choose-btn="false"
      :box-width="560"
      :box-height="360"
      :cut-width="240"
      :cut-height="240"
      :size-change="false"
      :img-move="true"
      :scale-able="true"
      file-type="png"
      @cutDown="handleAvatarCutDown"
      @onClearAll="handleAvatarClearAll"
    >
      <template #open>
        <span></span>
      </template>
      <template #choose>
        <ElButton type="primary" plain v-ripple>{{ t('user.avatar.upload') }}</ElButton>
      </template>
      <template #cancel>
        <ElButton type="danger" plain v-ripple>{{ t('user.action.cancel') }}</ElButton>
      </template>
      <template #confirm>
        <ElButton type="primary" v-ripple>{{ t('user.action.confirm') }}</ElButton>
      </template>
    </ImgCutter>
    <template #footer>
      <div class="dialog-footer">
        <ElButton :disabled="loading" @click="dialogVisible = false">
          {{ t('user.action.cancel') }}
        </ElButton>
        <ElButton type="primary" :loading="loading" @click="handleSubmit">
          {{ t('user.action.confirm') }}
        </ElButton>
      </div>
    </template>
  </ElDialog>
</template>

<script setup lang="ts">
  import type { FormInstance, FormRules } from 'element-plus'
  import { useI18n } from 'vue-i18n'
  import ImgCutter from 'vue-img-cutter'
  import { fetchUploadFile } from '@/api/files'

  defineOptions({ name: 'UserDialog' })

  // 1. 组件入参定义
  interface SelectOption {
    label: string
    value: string | number
    disabled?: boolean
  }

  interface CutterResult {
    fileName: string
    file?: File
    blob?: Blob
    dataURL: string
  }

  type DialogType = 'add' | 'edit'

  type UserDialogSubmitPayload =
    | { type: 'add'; data: Api.SystemManage.CreateIdentityUserCommand }
    | { type: 'edit'; data: Api.SystemManage.UpdateIdentityUserCommand }

  interface Props {
    visible: boolean
    type: DialogType
    userData?: Api.SystemManage.UserDetailDto | null
    roleOptions: SelectOption[]
    tenantOptions: SelectOption[]
    statusOptions: SelectOption[]
    isSuperAdmin: boolean
    defaultTenantId?: string
    loading?: boolean
  }

  interface Emits {
    (e: 'update:visible', value: boolean): void
    (e: 'submit', payload: UserDialogSubmitPayload): void
    (e: 'tenant-change', tenantId?: string): void
  }

  const props = defineProps<Props>()
  const emit = defineEmits<Emits>()

  // 2. 国际化与对话框状态
  const { t } = useI18n()
  const dialogVisible = computed({
    get: () => props.visible,
    set: (value) => emit('update:visible', value)
  })

  const isAdd = computed(() => props.type === 'add')
  const isEdit = computed(() => props.type === 'edit')
  const showTenantField = computed(() => props.isSuperAdmin)
  const dialogTitle = computed(() =>
    isAdd.value ? t('user.dialog.createTitle') : t('user.dialog.editTitle')
  )

  // 3. 表单模型与校验规则
  const formRef = ref<FormInstance>()
  const formData = reactive({
    tenantId: '',
    account: '',
    displayName: '',
    password: '',
    phone: '',
    email: '',
    avatar: '',
    roleIds: [] as string[],
    status: 1 as Api.SystemManage.IdentityUserStatus,
    rowVersion: ''
  })

  const rules = computed<FormRules>(() => ({
    tenantId: showTenantField.value
      ? [{ required: true, message: t('user.validation.tenantRequired'), trigger: 'change' }]
      : [],
    account: [{ required: true, message: t('user.validation.accountRequired'), trigger: 'blur' }],
    displayName: [
      { required: true, message: t('user.validation.displayNameRequired'), trigger: 'blur' }
    ],
    password: isAdd.value
      ? [
          { required: true, message: t('user.validation.passwordRequired'), trigger: 'blur' },
          { min: 6, max: 32, message: t('user.validation.passwordLength'), trigger: 'blur' }
        ]
      : [],
    phone: [
      {
        pattern: /^1[3-9]\d{9}$/,
        message: t('user.validation.phoneInvalid'),
        trigger: 'blur'
      }
    ],
    email: [
      {
        type: 'email',
        message: t('user.validation.emailInvalid'),
        trigger: 'blur'
      }
    ]
  }))

  // 4. 头像裁剪与上传
  const avatarInputRef = ref<HTMLInputElement | null>(null)
  const avatarCutterRef = ref<{
    handleOpen: (img: { name: string; src: string }) => void
    handleClose: () => void
  } | null>(null)
  const avatarUploading = ref(false)
  const avatarFileName = ref('')
  const avatarTempUrl = ref('')

  watch(
    () => formData.avatar,
    () => {
      // 1. 外部清空时同步清理文件名展示
      if (!formData.avatar) {
        avatarFileName.value = ''
      }
    }
  )

  const openAvatarDialog = () => {
    // 1. 触发隐藏 input 选择文件
    avatarInputRef.value?.click()
  }

  const handleAvatarChange = async (event: Event) => {
    // 1. 获取文件
    const target = event.target as HTMLInputElement
    const file = target.files?.[0]
    if (!file) return

    // 2. 清空 input，支持重复选择同一文件
    target.value = ''

    // 3. 打开裁剪器
    openAvatarCutter(file)
  }

  const openAvatarCutter = (file: File) => {
    // 1. 清理旧 URL
    clearAvatarTempUrl()

    // 2. 打开裁剪弹窗
    const url = URL.createObjectURL(file)
    avatarTempUrl.value = url
    avatarCutterRef.value?.handleOpen({ name: file.name, src: url })
  }

  const handleAvatarCutDown = async (result: CutterResult) => {
    // 1. 避免并发上传
    if (avatarUploading.value) return

    // 2. 调用上传接口
    avatarUploading.value = true
    try {
      const uploadFile = result.file
        ? result.file
        : result.blob
          ? new File([result.blob], result.fileName || 'avatar.png', {
              type: result.blob.type || 'image/png'
            })
          : null
      if (!uploadFile) {
        return
      }
      const res = await fetchUploadFile(uploadFile, 'user_avatar')
      const url = res.url || ''
      if (!url) {
        return
      }

      avatarFileName.value = res.fileName || uploadFile.name
      formData.avatar = url
    } finally {
      avatarUploading.value = false
      clearAvatarTempUrl()
      avatarCutterRef.value?.handleClose()
    }
  }

  const handleAvatarClearAll = () => {
    // 1. 清理临时 URL
    clearAvatarTempUrl()
  }

  const clearAvatarTempUrl = () => {
    // 1. 释放旧 URL
    if (avatarTempUrl.value) {
      URL.revokeObjectURL(avatarTempUrl.value)
      avatarTempUrl.value = ''
    }
  }

  const handleAvatarRemove = () => {
    // 1. 清空 URL（仅前端移除，不做后端删除）
    formData.avatar = ''
  }

  // 5. 初始化表单数据
  const initFormData = () => {
    // 1. 解析详情与默认租户
    const detail = props.userData
    const defaultTenantId = String(props.defaultTenantId || props.tenantOptions[0]?.value || '')

    // 2. 编辑模式填充
    if (isEdit.value && detail) {
      formData.tenantId = detail.tenantId || ''
      formData.account = detail.account || ''
      formData.displayName = detail.displayName || ''
      formData.password = ''
      formData.phone = detail.phone || ''
      formData.email = detail.email || ''
      formData.avatar = detail.avatar || ''
      avatarFileName.value = ''
      formData.roleIds = Array.isArray(detail.roleIds)
        ? detail.roleIds.map((roleId) => String(roleId))
        : []
      formData.status = detail.status
      formData.rowVersion = detail.rowVersion || ''
      return
    }

    // 3. 新增模式初始化
    formData.tenantId = String(detail?.tenantId || defaultTenantId || '')
    formData.account = ''
    formData.displayName = ''
    formData.password = ''
    formData.phone = ''
    formData.email = ''
    formData.avatar = ''
    avatarFileName.value = ''
    formData.roleIds = []
    formData.status = 1
    formData.rowVersion = ''
  }

  // 6. 监听弹窗状态初始化
  watch(
    () => [props.visible, props.type, props.userData],
    ([visible]) => {
      // 1. 仅在弹窗显示时初始化
      if (!visible) return
      initFormData()

      // 2. 重置校验状态
      nextTick(() => formRef.value?.clearValidate())
    },
    { immediate: true }
  )

  // 7. 监听租户变化加载角色
  watch(
    () => formData.tenantId,
    (value) => {
      // 1. 非超级管理员不触发
      if (!showTenantField.value) return
      emit('tenant-change', value || undefined)
    }
  )

  // 8. 构建提交数据
  const buildSubmitPayload = (): UserDialogSubmitPayload => {
    // 1. 新增模式提交
    if (isAdd.value) {
      return {
        type: 'add',
        data: {
          tenantId: formData.tenantId || undefined,
          account: formData.account.trim(),
          displayName: formData.displayName.trim(),
          password: formData.password,
          phone: formData.phone.trim() || undefined,
          email: formData.email.trim() || undefined,
          avatar: formData.avatar.trim() || undefined,
          roleIds: formData.roleIds,
          status: formData.status
        }
      }
    }

    // 2. 编辑模式提交
    return {
      type: 'edit',
      data: {
        tenantId: formData.tenantId || undefined,
        displayName: formData.displayName.trim(),
        phone: formData.phone.trim() || undefined,
        email: formData.email.trim() || undefined,
        avatar: formData.avatar.trim() || undefined,
        roleIds: formData.roleIds,
        rowVersion: formData.rowVersion
      }
    }
  }

  // 9. 提交表单
  const handleSubmit = async () => {
    // 1. 校验表单
    if (!formRef.value) return
    const valid = await formRef.value.validate()
    if (!valid) return

    // 2. 触发提交
    emit('submit', buildSubmitPayload())
  }
</script>
