<template>
  <ElDialog
    v-model="visible"
    :title="$t('billing.dialog.recordPaymentTitle')"
    width="600px"
    destroy-on-close
    @close="handleClose"
  >
    <ElForm ref="formRef" :model="formData" :rules="rules" label-width="120px" v-loading="loading">
      <ElFormItem :label="$t('billing.payment.amount')" prop="amount">
        <ElInputNumber
          v-model="formData.amount"
          :placeholder="$t('billing.placeholder.enterPaymentAmount')"
          :min="0.01"
          :max="remainAmount"
          :precision="2"
          style="width: 100%"
        />
        <div class="text-sm text-gray-500 mt-1">
          {{ $t('billing.payment.remainAmount') }}: ¥{{ remainAmount.toFixed(2) }}
        </div>
      </ElFormItem>

      <ElFormItem :label="$t('billing.payment.method')" prop="method">
        <ElSelect
          v-model="formData.method"
          :placeholder="$t('billing.placeholder.selectPaymentMethod')"
          style="width: 100%"
        >
          <ElOption
            v-for="method in methodOptions"
            :key="method.value"
            :label="method.label"
            :value="method.value"
          />
        </ElSelect>
      </ElFormItem>

      <ElFormItem :label="$t('billing.payment.transactionNo')" prop="transactionNo">
        <ElInput
          v-model="formData.transactionNo"
          :placeholder="$t('billing.placeholder.enterTransactionNo')"
        />
      </ElFormItem>

      <ElFormItem :label="$t('billing.payment.proofUrl')" prop="proofUrl">
        <div class="w-full flex flex-col gap-1">
          <ElUpload
            v-model:file-list="fileList"
            :limit="1"
            :accept="acceptTypes"
            :http-request="handleUploadRequest"
            :before-upload="handleBeforeUpload"
            :on-preview="handlePreview"
            :on-remove="handleRemove"
          >
            <ElButton type="primary" plain v-ripple>{{
              $t('billing.action.uploadProof')
            }}</ElButton>
          </ElUpload>
          <div class="text-xs leading-5 text-[var(--el-text-color-secondary)] break-words">
            {{ $t('billing.payment.proofUploadHint') }}
          </div>
        </div>
      </ElFormItem>

      <ElFormItem :label="$t('billing.payment.notes')" prop="notes">
        <ElInput
          v-model="formData.notes"
          type="textarea"
          :rows="3"
          :placeholder="$t('billing.placeholder.enterPaymentNotes')"
        />
      </ElFormItem>
    </ElForm>

    <template #footer>
      <div class="dialog-footer">
        <ElButton @click="handleClose">{{ $t('common.cancel') }}</ElButton>
        <ElButton type="primary" @click="handleSubmit" :loading="loading" v-ripple>
          {{ $t('common.confirm') }}
        </ElButton>
      </div>
    </template>
  </ElDialog>

  <!-- 1. 凭证预览弹窗 -->
  <ElDialog v-model="previewVisible" :title="$t('billing.dialog.proofPreviewTitle')" width="800px">
    <div v-if="previewUrl" class="w-full">
      <ElImage :src="previewUrl" fit="contain" class="w-full max-h-[70vh]" />
    </div>
  </ElDialog>
</template>

<script setup lang="ts">
  import { ref, reactive } from 'vue'
  import { useI18n } from 'vue-i18n'
  import {
    ElMessage,
    ElDialog,
    ElForm,
    ElFormItem,
    ElSelect,
    ElOption,
    ElInputNumber,
    ElInput,
    ElButton,
    ElUpload,
    ElImage
  } from 'element-plus'
  import type { FormInstance, FormRules, UploadRequestOptions, UploadUserFile } from 'element-plus'
  import { confirmPayment } from '@/api/billing'
  import { fetchUploadFile } from '@/api/files'
  import { TenantPaymentMethod } from '@/enums/Billing'

  defineOptions({ name: 'RecordPaymentDialog' })

  const { t } = useI18n()
  const emit = defineEmits<{
    success: [billingId: string]
  }>()

  // 1. 枚举（运行时枚举以 src/enums 为准）

  // 2. 响应式状态
  const visible = ref(false)
  const loading = ref(false)
  const formRef = ref<FormInstance>()
  const billId = ref('')
  const remainAmount = ref(0)

  // 3. 表单数据
  const formData = reactive({
    amount: 0,
    method: TenantPaymentMethod.BankTransfer,
    transactionNo: '',
    proofUrl: '',
    notes: ''
  })

  // 4. 凭证上传与预览
  const acceptTypes = 'image/jpeg,image/png'
  const fileList = ref<UploadUserFile[]>([])
  const previewVisible = ref(false)
  const previewUrl = ref('')

  // 5. 支付方式选项
  const methodOptions = ref([
    { label: t('billing.paymentMethod.online'), value: TenantPaymentMethod.Online },
    { label: t('billing.paymentMethod.bankTransfer'), value: TenantPaymentMethod.BankTransfer },
    { label: t('billing.paymentMethod.other'), value: TenantPaymentMethod.Other }
  ])

  // 6. 验证规则
  const rules: FormRules = {
    amount: [
      { required: true, message: t('billing.validation.paymentAmountRequired'), trigger: 'blur' },
      {
        type: 'number',
        min: 0.01,
        message: t('billing.validation.paymentAmountMin'),
        trigger: 'blur'
      },
      {
        validator: (_rule, value, callback) => {
          const v = Number(value || 0)
          if (v > remainAmount.value) {
            callback(new Error(t('billing.validation.paymentAmountExceedRemain')))
            return
          }
          callback()
        },
        trigger: 'blur'
      }
    ],
    method: [
      { required: true, message: t('billing.validation.paymentMethodRequired'), trigger: 'change' }
    ]
  }

  // 7. 上传与预览
  // 7.1 上传前校验（类型/大小）
  const handleBeforeUpload = (file: File) => {
    const isAllowed = file.type === 'image/jpeg' || file.type === 'image/png'
    if (!isAllowed) {
      ElMessage.warning(t('billing.message.proofTypeNotAllowed'))
      return false
    }

    const maxSizeMb = 10
    const isSizeOk = file.size / 1024 / 1024 <= maxSizeMb
    if (!isSizeOk) {
      ElMessage.warning(t('billing.message.proofTooLarge', { size: maxSizeMb }))
      return false
    }

    return true
  }

  // 7.2 自定义上传（保存 URL 到 TenantPayment.ProofUrl -> proofUrl）
  const handleUploadRequest = async (options: UploadRequestOptions) => {
    try {
      const res = await fetchUploadFile(options.file as File, 'other')
      const url = res.url || ''
      if (!url) {
        throw new Error('Upload response missing url')
      }

      formData.proofUrl = url
      fileList.value = [{ name: (options.file as File).name, url }]
      options.onSuccess?.(res as unknown as Record<string, unknown>)
      ElMessage.success(t('billing.message.proofUploadSuccess'))
    } catch (error) {
      console.error('Upload proof error:', error)
      const err = error instanceof Error ? error : new Error(String(error))
      type UploadError = Parameters<NonNullable<UploadRequestOptions['onError']>>[0]
      const ajaxError = Object.assign(err, {
        status: 500,
        method: 'POST',
        url: ''
      })
      options.onError?.(ajaxError as unknown as UploadError)
    }
  }

  // 7.3 预览（jpg/png）
  const handlePreview = (file: UploadUserFile) => {
    const url = file.url || ''
    if (!url) return

    previewUrl.value = url
    previewVisible.value = true
  }

  // 7.4 移除凭证
  const handleRemove = () => {
    formData.proofUrl = ''
  }

  // 8. 提交表单
  const handleSubmit = async () => {
    if (!formRef.value) return

    try {
      await formRef.value.validate()

      loading.value = true
      await confirmPayment(billId.value, formData)

      ElMessage.success(t('billing.message.recordPaymentSuccess'))
      emit('success', billId.value)
      visible.value = false
    } catch (error) {
      console.error('Record payment error:', error)
    } finally {
      loading.value = false
    }
  }

  // 9. 关闭对话框
  const handleClose = () => {
    formRef.value?.resetFields()
    fileList.value = []
    previewVisible.value = false
    previewUrl.value = ''
    visible.value = false
  }

  // 10. 打开对话框
  const open = (id: string, remain: number) => {
    billId.value = id
    remainAmount.value = remain
    formData.amount = remain
    formData.proofUrl = ''
    fileList.value = []
    visible.value = true
  }

  // 11. 暴露方法
  defineExpose({ open })
</script>

<style scoped lang="scss">
  .dialog-footer {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
  }
</style>
