<script setup lang="ts">
// import cameraIcon from '@af-mobile-client-vue3/assets/img/component/camera.png'
import { deleteFile, upload } from '@af-mobile-client-vue3/services/api/common'
import { detectEnvironment } from '@af-mobile-client-vue3/utils/environment'
import { mobileUtil } from '@af-mobile-client-vue3/utils/mobileUtil'
import { formatNow } from '@af-mobile-client-vue3/utils/timeUtil'
import {
  ActionSheet,
  showDialog,
  showFailToast,
  Icon as VanIcon,
  Uploader as vanUploader,
} from 'vant'
import { inject, onBeforeUnmount, ref } from 'vue'

interface WatermarkConfig {
  fontSize?: number | string
  color?: string
  alpha?: number
  userName?: string
  format?: string
  customLines?: string[]
  enableRePhotoCheck?: boolean
  blurThreshold?: string | number
}

interface ImageUploaderProps {
  imageList?: any[]
  outerIndex?: number | undefined
  authority?: string
  uploadMode?: string
  attr?: {
    addOrEdit?: string
    acceptCount?: number
    minAcceptCount?: number
    uploadImage?: boolean
    watermark?: WatermarkConfig
    useType?: string
  }
  mode?: string
  serviceName?: string
  readonly?: boolean
  isAsyncUpload?: boolean
}

const props = withDefaults(defineProps<ImageUploaderProps>(), {
  imageList: () => [],
  outerIndex: undefined,
  authority: 'user',
  uploadMode: 'server',
  attr: () => ({}),
  mode: '新增',
  serviceName: '',
  // 整体只读：只允许预览，禁止拍照/上传/删除
  readonly: false,
  isAsyncUpload: false,
})
const emit = defineEmits(['updateFileList', 'updateAllFileList', 'photoQualityChange'])

const imageList = ref<Array<any>>(props.imageList ?? [])

// 从父组件获取 commonId，仅读取一次而非持有引用
const parentCommonId = (() => {
  try {
    const parent = inject<any>('provideParent', undefined)
    return parent?.commonId?.value ?? ''
  }
  catch {
    return ''
  }
})()

// 浏览器 / 微信内 H5：统一用隐藏 file input（与单独 camera input 行为等价，均为系统选图）
const fileInputRef = ref<HTMLInputElement | undefined>()

function openBrowserFilePicker() {
  if (fileInputRef.value) {
    fileInputRef.value.value = ''
    fileInputRef.value.click()
  }
}

function emitUpdatesAfterChange() {
  // 新增：对外抛出完整与ID列表
  (emit as any)('updateAllFileList', imageList.value.filter(item => item.status === 'done').map(item => item))
  const doneIds = Object.values(imageList.value)
    .filter(item => item.status === 'done')
    .map(item => item.id)
  if (props.outerIndex !== undefined) {
    (emit as any)('updateFileList', doneIds, props.outerIndex, imageList.value)
  }
  else {
    (emit as any)('updateFileList', doneIds, imageList.value)
  }
}

function createTempUploadingItem(name: string, previewUrl: string) {
  const temp = {
    uid: Date.now() + Math.random().toString(36).substr(2, 5),
    name,
    status: 'uploading',
    message: '上传中...',
    url: previewUrl,
  }
  if (!imageList.value)
    imageList.value = [temp]
  else imageList.value.push(temp)
  return temp
}

function uploadFileViaHttp(file: File, previewUrl: string, temp: any) {
  const formData = new FormData()
  formData.append('avatar', file)
  formData.append('resUploadMode', props.uploadMode)
  formData.append('pathKey', 'Default')
  formData.append('formType', 'image')
  formData.append('useType', 'Default')
  formData.append('resUploadStock', '1')
  formData.append('filename', file.name)
  formData.append('filesize', (file.size / 1024 / 1024).toFixed(4))
  formData.append('f_operator', 'server')

  upload(formData, props.serviceName || import.meta.env.VITE_APP_SYSTEM_NAME, { 'Content-Type': 'multipart/form-data' }).then((res: any) => {
    const index = imageList.value.findIndex((item) => {
      if (temp.uid && item.uid === temp.uid)
        return true
      if (item === temp)
        return true
      return !!(temp.url && item.url === temp.url && item.status === 'uploading')
    })
    if (res?.data?.id) {
      if (index !== -1) {
        imageList.value[index].uid = res.data.id
        imageList.value[index].id = res.data.id
        delete imageList.value[index].message
        imageList.value[index].status = 'done'
        imageList.value[index].url = `${import.meta.env.VITE_APP_RESOURCE_PATH || ''}${res.data.f_downloadpath}`
      }
    }
    else {
      if (index !== -1) {
        imageList.value[index].status = 'failed'
        imageList.value[index].message = '上传失败'
      }
    }
    emitUpdatesAfterChange()
  })
}

function buildWatermarkText() {
  const wm = (props.attr as any)?.watermark ?? {}
  const user = wm.userName ?? ''
  const time = formatNow(wm.format || 'YYYY-MM-DD HH:mm:ss')
  const lines: string[] = []
  if (user)
    lines.push(`拍摄人：${user}`)
  if (time)
    lines.push(`拍摄时间：${time}`)
  if (Array.isArray(wm.customLines) && wm.customLines.length > 0)
    lines.push(...wm.customLines.filter((v: any) => typeof v === 'string' && v !== ''))
  return lines.join('\n')
}

function handleBrowserFiles(files: FileList | null) {
  if (!files || files.length === 0)
    return
  const max = props.attr?.acceptCount ?? Number.POSITIVE_INFINITY
  for (let i = 0; i < files.length; i++) {
    if (imageList.value.length >= max)
      break
    const file = files[i]
    const reader = new FileReader()
    reader.onload = (e: any) => {
      const previewUrl = e.target?.result as string
      const temp = createTempUploadingItem(file.name, previewUrl)
      uploadFileViaHttp(file, previewUrl, temp)
    }
    reader.readAsDataURL(file)
  }
}

// 触发拍照
function triggerCamera() {
  mobileUtil.execute({
    funcName: 'takePicture',
    param: (() => {
      const param: any = {}
      const watermark = { ...(props.attr as any)?.watermark }
      if (watermark) {
        const txt = buildWatermarkText()
        if (txt)
          param.watermark = txt
        if (watermark.fontSize !== undefined && String(watermark.fontSize) !== '')
          param.watermarkFontSize = watermark.fontSize
        if (watermark.color)
          param.watermarkColor = watermark.color
        if (watermark.alpha !== undefined && String(watermark.alpha) !== '')
          param.watermarkAlpha = watermark.alpha
      }
      param.blurThreshold = (props.attr as any)?.watermark?.blurThreshold ?? 30
      return param
    })(),
    callbackFunc: (result: any) => {
      if (result.status === 'success') {
        rePhotoCheck(result.data)
      }
      else if (result.status === 'error') {
        if (result?.message && result.message.startsWith('图片质量检测失败')) {
          emit('photoQualityChange', 'quality-failed')
        }
        const env = detectEnvironment()
        // App 环境下弹窗提示错误
        if (env.isApp) {
          showDialog({
            title: '拍照异常',
            message: result.message || '拍照失败，请重试',
          })
          return
        }
        // 浏览器模式：打开文件选择
        openBrowserFilePicker()
      }
    },
  })
}

/**
 * 检测并上传图片
 * @param photoData
 */
function rePhotoCheck(photoData: any) {
  // 看看图片是否正常
  console.log('图片参数:', photoData)
  console.log('图片参数:', JSON.stringify(photoData))

  // 检查是否需要进行翻拍检测（只有拍照的图片才检测）
  const watermark = (props.attr as any)?.watermark
  const enableRePhotoCheck = watermark?.enableRePhotoCheck ?? false
  console.warn('enableRePhotoCheck', enableRePhotoCheck)

  if (enableRePhotoCheck) {
    // 进行翻拍检测
    mobileUtil.execute({
      funcName: 'detectAntiCopy',
      param: {
        image_base64: photoData.content,
      },
      callbackFunc: (result: any) => {
        try {
          console.log('翻拍检测结果:', JSON.stringify(result))
          if (result && result.status === 'success') {
            const checkRePhotoResult = result.data
            if (checkRePhotoResult.is_rephoto === true || checkRePhotoResult.is_rephoto === 'true') {
              emit('photoQualityChange', 'rephoto-detected')
              console.warn(`检测到当前图片属于翻拍照片\n请上传合法图片！`)
              showFailToast({
                message: `当前图片属于翻拍照片\n请上传合法图片！`,
                duration: 3000,
              })
            }
            else {
              handlePhotoUpload(photoData)
            }
          }
          else {
            console.error(`翻拍检测失败照片,${result.message}`)
            showFailToast(`翻拍检测失败照片,${result.message}`)
          }
        }
        catch (e) {
          console.error('翻拍检测', JSON.stringify(e))
        }
      },
    })
  }
  else {
    handlePhotoUpload(photoData)
  }
}

// 处理拍照后的上传
function getImageMimeType(fileName: string): string {
  const ext = fileName.split('.').pop()?.toLowerCase()
  if (ext === 'jpg' || ext === 'jpeg')
    return 'image/jpeg'
  if (ext === 'png')
    return 'image/png'
  if (ext === 'gif')
    return 'image/gif'
  return 'image/png' // 默认
}

function handlePhotoUpload(photoData: any) {
  // 看看图片是否正常
  console.log('图片上传前的参数:', photoData)
  console.log('图片上传前的参数:', JSON.stringify(photoData))
  // 添加临时预览
  const mimeType = getImageMimeType(photoData.filePath)
  const tempFile = {
    uid: Date.now() + Math.random().toString(36).substr(2, 5),
    name: photoData.filePath.split('/').pop(),
    status: 'uploading',
    message: '上传中...',
    url: `data:${mimeType};base64,${photoData.content}`,
    content: `data:image/png;base64,${photoData.content}`,
    isImage: true,
    type: mimeType,
  }

  if (!imageList.value) {
    imageList.value = [tempFile]
  }
  else {
    imageList.value.push(tempFile)
  }

  const param = {
    resUploadMode: props.uploadMode,
    pathKey: 'Default',
    formType: 'image',
    useType: props.attr?.useType || 'Default',
    resUploadStock: '1',
    filename: photoData.name,
    filesize: photoData.size,
    f_operator: 'server',
    imgPath: photoData.filePath,
    urlPath: `/api/${props.serviceName || import.meta.env.VITE_APP_SYSTEM_NAME}/resource/upload`,
    commonId: parentCommonId,
  }
  if (props.isAsyncUpload) {
    // 添加上传队列
    mobileUtil.execute({
      funcName: 'queueUpload',
      param,
      callbackFunc: (res: any) => {
        console.warn('上传结果', res)
        // 成功
        if (res.data && res.data.enqueued) {
          const index = imageList.value.findIndex(item => item.uid === tempFile.uid)
          console.log('index--------', index)
          if (index !== -1) {
            delete imageList.value[index].message
            imageList.value[index].status = 'done'
            imageList.value[index].photo_name = photoData.name
            imageList.value[index].type = mimeType
          }
          else {
            if (index !== -1) {
              imageList.value[index].status = 'failed'
              imageList.value[index].message = '上传失败'
            }
          }
        }

        emit('updateAllFileList', imageList.value.filter(item => item.status === 'done').map(item => item)) // 新增

        const doneIds = Object.values(imageList.value)
          .filter(item => !item.status || item.status === 'done')
          .map(item => item.photo_name)

        if (props.outerIndex !== undefined)
          emit('updateFileList', doneIds, props.outerIndex, imageList.value)
        else
          emit('updateFileList', doneIds, imageList.value)
      },
    })
  }
  else {
    // 上传到服务器
    mobileUtil.execute({
      funcName: 'uploadResource',
      param,
      callbackFunc: (result: any) => {
        const index = imageList.value.findIndex(item => item.uid === tempFile.uid)
        if (result.status === 'success') {
          if (index !== -1) {
            imageList.value[index].uid = result.data.id
            imageList.value[index].id = result.data.id
            delete imageList.value[index].message
            imageList.value[index].status = 'done'
            imageList.value[index].url = `${import.meta.env.VITE_APP_RESOURCE_PATH || ''}${result.data.f_downloadpath}`
          }
        }
        else {
          if (index !== -1) {
            imageList.value[index].status = 'failed'
            imageList.value[index].message = '上传失败'
          }
        }

        emit('updateAllFileList', imageList.value.filter(item => item.status === 'done').map(item => item)) // 新增

        const doneIds = Object.values(imageList.value)
          .filter(item => item.status === 'done')
          .map(item => item.id)

        if (props.outerIndex !== undefined)
          emit('updateFileList', doneIds, props.outerIndex, imageList.value)
        else
          emit('updateFileList', doneIds, imageList.value)
      },
    })
  }
}

// 删除图片
function deleteFileFunction(file: any) {
  // 情况1：有后端id的已上传文件，先调接口再本地移除
  if (file.id) {
    deleteFile({ ids: [file.id], f_state: '删除' }).then((res: any) => {
      if (res.msg !== undefined) {
        const targetIndex = imageList.value.findIndex(item => item.id === file.id)
        if (targetIndex !== -1)
          imageList.value.splice(targetIndex, 1)

        emit('updateAllFileList', imageList.value.filter(item => item.status === 'done').map(item => item))

        const doneIds = ref(null)
        if (props.isAsyncUpload) {
          doneIds.value = Object.values(imageList.value)
            .filter(item => !item.status || item.status === 'done')
            .map(item => item.photo_name)
        }
        else {
          doneIds.value = Object.values(imageList.value)
            .filter(item => item.status === 'done')
            .map(item => item.id)
        }
        if (props.outerIndex !== undefined)
          emit('updateFileList', doneIds.value, props.outerIndex)
        else
          emit('updateFileList', doneIds.value, imageList.value)
      }
    })
    return false // 已手动移除，阻止van-uploader再次移除
  }

  // 情况2：上传失败/上传中的临时文件（无id），允许直接删除
  const targetIndex = imageList.value.findIndex(item => item.uid === file.uid || item.url === file.url)
  if (targetIndex !== -1)
    imageList.value.splice(targetIndex, 1)

  emit('updateAllFileList', imageList.value.filter(item => item.status === 'done').map(item => item))

  const doneIds = ref(null)
  if (props.isAsyncUpload) {
    doneIds.value = Object.values(imageList.value)
      .filter(item => !item.status || item.status === 'done')
      .map(item => item.photo_name)
  }
  else {
    doneIds.value = Object.values(imageList.value)
      .filter(item => item.status === 'done')
      .map(item => item.id)
  }
  if (props.outerIndex !== undefined)
    emit('updateFileList', doneIds.value, props.outerIndex)
  else
    emit('updateFileList', doneIds.value)

  return false // 阻止van-uploader二次处理
}

const showActionSheet = ref(false)
const uploaderRef = ref()

const actionOptions = [
  { name: '拍照', key: 'camera' },
  { name: '上传', key: 'file' },
]

function handleUploadAreaClick() {
  if (props.readonly)
    return
  const env = detectEnvironment()
  // 微信内：直接走浏览器式文件选择，不弹出拍照/上传菜单
  if (env.isWechat || env.isMiniprogram) {
    openBrowserFilePicker()
    return
  }
  if (props.attr?.uploadImage) {
    showActionSheet.value = true
  }
  else {
    triggerCamera()
  }
}

function handleActionSelect(option: any) {
  showActionSheet.value = false
  if (option.key === 'camera') {
    triggerCamera()
  }
  else if (option.key === 'file') {
    // 手机文件上传
    mobileUtil.execute({
      funcName: 'photoAlbum',
      param: {},
      callbackFunc: (result: any) => {
        if (result.status === 'success') {
          result.data?.photos.forEach((photo: any) => {
            rePhotoCheck(photo)
          })
        }
        else {
          // 手机文件选择失败，则走浏览器式文件选择
          openBrowserFilePicker()
        }
      },
    })
  }
}

function getUploadStatus() {
  // 暴露给父组件的上传进度统计：上传中/成功/失败以及是否全部完成
  const totalCount = imageList.value.length
  const uploadingCount = imageList.value.filter(item => item.status === 'uploading').length
  const failedCount = imageList.value.filter(item => item.status === 'failed').length
  const successCount = imageList.value.filter(item => !item.status || item.status === 'done').length
  return {
    allUploaded: successCount === totalCount,
    uploadingCount,
    successCount,
    failedCount,
    totalCount,
  }
}

defineExpose({
  getUploadStatus,
})

/**
 * 组件卸载时清理：关闭 ActionSheet，清空图片列表以释放闭包引用
 */
onBeforeUnmount(() => {
  showActionSheet.value = false
  // 清空图片列表，释放闭包中对 props.attr 等对象的引用，防止内存泄漏
  imageList.value = []
})
</script>

<template>
  <div class="uploader-container">
    <!-- 浏览器 / 微信 H5：统一隐藏文件选择（多选图片） -->
    <input
      ref="fileInputRef"
      type="file"
      multiple
      accept="image/*"
      style="display:none"
      @change="(e:any) => handleBrowserFiles(e.target.files)"
    >
    <van-uploader
      ref="uploaderRef"
      v-model="imageList"
      class="custom-trigger-uploader"
      :show-upload="true"
      :deletable="!props.readonly && (props.attr?.addOrEdit !== 'readonly' && props.authority === 'admin') && props.mode !== '预览'"
      :multiple="!props.readonly && props.authority === 'admin'"
      :preview-image="true"
      :before-delete="!props.readonly && props.attr?.addOrEdit !== 'readonly' && props.authority === 'admin' ? deleteFileFunction : undefined"
    >
      <template #default>
        <div
          v-if="!props.readonly && props.mode !== '预览' && (imageList.length < props.attr?.acceptCount && props.attr?.addOrEdit !== 'readonly')"
          class="custom-upload-area"
          @click="handleUploadAreaClick"
        >
          <VanIcon name="plus" size="35" color="#d9d9d9" />
          <div v-if="props.attr?.acceptCount" class="upload-desc">
            {{ imageList.length }} / {{ props.attr?.minAcceptCount ? `(${props.attr?.minAcceptCount}~${props.attr?.acceptCount})` : `${props.attr?.acceptCount}` }}
          </div>
        </div>
      </template>
    </van-uploader>
    <ActionSheet
      v-model:show="showActionSheet"
      :actions="actionOptions"
      teleport="body"
      cancel-text="取消"
      @select="handleActionSelect"
    />
  </div>
</template>

<style scoped lang="less">
.uploader-container {
  display: flex;
  flex-direction: column;
  // 默认图片上传区域高度会影响布局
  width: 100%;
  height: 100%;
  // 该属性会影响表单布局
  // gap: 16px;
}
/* 让自定义上传按钮可点击：关闭 Vant 覆盖在上方的透明 input 的事件捕获 */
:deep(.custom-trigger-uploader .van-uploader__input) {
  pointer-events: none;
}
.custom-upload-area {
  width: 82px;
  height: 82px;
  box-sizing: border-box;
  border: 1px dashed #d9d9d9;
  border-radius: 10px;
  background: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 8px 4px;
  flex: 1;
  .upload-camera-img {
    width: 28px;
    height: 28px;
    margin-bottom: 6px;
    object-fit: contain;
    display: block;
  }
  .upload-title {
    font-size: 14px;
    color: #bfc1c6;
    font-weight: 400;
    margin-bottom: 2px;
  }
  .upload-desc {
    font-size: 12px;
    color: #bfc1c6;
    margin-top: 0;
  }
}
</style>
