<template>
  <view class="image-uploader">
    <!-- 已上传图片列表 -->
    <view class="flex flex-wrap gap-2">
      <view
        v-for="(item, index) in normalizedList"
        :key="item.id || item.url || index"
        class="relative w-20 h-20 rounded-lg overflow-hidden border border-gray-200"
      >
        <image
          :src="item.url"
          style="width: 160rpx; height: 160rpx;"
          class="object-cover block"
          mode="aspectFill"
          @click="previewImage(index)"
        />
        <view
          v-if="!disabled"
          class="absolute top-0 right-0 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center -mt-1 -mr-1 z-10"
          @click="removeImage(index)"
        >
          <text class="uni-icons uniui-close text-white text-xs"></text>
        </view>
      </view>

      <!-- 上传按钮 -->
      <view
        v-if="!disabled && normalizedList.length < maxCount"
        class="w-20 h-20 rounded-lg border-2 border-dashed border-gray-300 flex flex-col items-center justify-center cursor-pointer bg-gray-50"
        @click="chooseImage"
      >
        <text class="uni-icons uniui-camera-filled text-gray-400 text-xl"></text>
        <text class="text-xs text-gray-400 mt-1">{{ normalizedList.length }}/{{ maxCount }}</text>
      </view>
    </view>

    <!-- 提示文字 -->
    <text v-if="tip" class="text-xs text-gray-400 mt-2 block">{{ tip }}</text>
  </view>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { uploadFile, uploadTaskPhoto, deleteTaskPhoto, type TaskPhoto } from '../../api/file'

export interface UploaderPhoto {
  id?: number | string
  url: string
}

interface Props {
  modelValue: Array<string | UploaderPhoto>
  maxCount?: number
  tip?: string
  /** 是否选择后立即上传 */
  autoUpload?: boolean
  /** taskPhoto 模式需要传入任务ID和步骤编码 */
  taskId?: number
  step?: string
  /** 上传类型：file-通用文件；taskPhoto-任务照片 */
  type?: 'file' | 'taskPhoto'
  /** 照片分组 phase（用于 admin 前端分组互通） */
  phase?: string
  /** 删除时是否同步后端 */
  syncDelete?: boolean
  /** 是否禁用上传与删除 */
  disabled?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  maxCount: 9,
  tip: '',
  autoUpload: true,
  type: 'file',
  syncDelete: true,
  disabled: false,
})

const emit = defineEmits<{
  'update:modelValue': [value: Array<string | UploaderPhoto>]
}>()

const uploadingSet = ref<Set<string>>(new Set())

const normalizedList = computed<UploaderPhoto[]>(() => {
  return props.modelValue.map((item) => {
    if (typeof item === 'string') return { url: item }
    return item
  })
})

function emitList(list: UploaderPhoto[]) {
  // 统一返回对象数组，保留 id 用于后端删除
  emit('update:modelValue', list)
}

function chooseImage() {
  const remainCount = props.maxCount - normalizedList.value.length
  if (remainCount <= 0) {
    uni.showToast({ title: '最多上传' + props.maxCount + '张', icon: 'none' })
    return
  }

  uni.chooseImage({
    count: remainCount,
    sizeType: ['compressed'],
    sourceType: ['album', 'camera'],
    success: async (res) => {
      const tempPaths = res.tempFilePaths as string[]
      const newItems: UploaderPhoto[] = tempPaths.map((url) => ({ url }))
      emitList([...normalizedList.value, ...newItems])
      if (props.autoUpload) {
        // 串行上传，避免并发覆盖列表状态
        let allSuccess = true
        for (const path of tempPaths) {
          const ok = await uploadOne(path)
          if (!ok) allSuccess = false
        }
        if (allSuccess) {
          uni.showToast({ title: '上传成功', icon: 'success' })
        }
      }
    },
  })
}

async function uploadOne(filePath: string): Promise<boolean> {
  uploadingSet.value.add(filePath)
  try {
    const url =
      props.type === 'taskPhoto' && props.taskId && props.step
        ? await uploadTaskPhoto(filePath, props.taskId, props.step, props.phase)
        : await uploadFile(filePath)

    const current = [...normalizedList.value]
    const idx = current.findIndex((item) => item.url === filePath)
    if (idx >= 0) {
      current[idx] = { ...current[idx], url }
      emitList(current)
      return true
    }
    return false
  } catch (e: any) {
    uni.showToast({ title: e.message || '上传失败', icon: 'none' })
    const current = normalizedList.value.filter((item) => item.url !== filePath)
    emitList(current)
    return false
  } finally {
    uploadingSet.value.delete(filePath)
  }
}

async function removeImage(index: number) {
  const item = normalizedList.value[index]
  if (!item) return

  if (props.syncDelete && item.id) {
    try {
      await deleteTaskPhoto(Number(item.id))
    } catch (e: any) {
      uni.showToast({ title: e.message || '删除失败', icon: 'none' })
      return
    }
  }

  const next = [...normalizedList.value]
  next.splice(index, 1)
  emitList(next)
}

function previewImage(index: number) {
  uni.previewImage({
    urls: normalizedList.value.map((item) => item.url),
    current: normalizedList.value[index]?.url,
  })
}
</script>
