<template>
  <view class="photo-uploader">
    <view class="flex flex-wrap gap-2">
      <view
        v-for="(url, index) in modelValue"
        :key="index"
        class="relative w-20 h-20 rounded-lg overflow-hidden border border-gray-200"
      >
        <image
          :src="url"
          style="width: 160rpx; height: 160rpx;"
          class="object-cover block"
          mode="aspectFill"
          @click="previewMedia(index)"
        />
        <view
          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="removeMedia(index)"
        >
          <text class="uni-icons uniui-close text-white text-xs"></text>
        </view>
      </view>

      <view
        v-if="modelValue.length < maxCount"
        class="w-20 h-20 rounded-lg border-2 border-dashed border-gray-300 flex flex-col items-center justify-center bg-gray-50"
        @click="chooseMedia"
      >
        <text class="uni-icons uniui-camera-filled text-gray-400 text-xl"></text>
        <text class="text-xs text-gray-400 mt-1">{{ modelValue.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 { chooseMediaCompat } from '../../utils'
import { uploadFile, uploadTaskPhoto } from '../../api/file'

const props = withDefaults(
  defineProps<{
    modelValue: string[]
    maxCount?: number
    tip?: string
    mediaType?: ('image' | 'video')[]
    /** 是否选择后立即上传 */
    autoUpload?: boolean
    /** taskPhoto 模式需要传入任务ID和步骤编码 */
    taskId?: number
    step?: string
    /** 上传类型：file-通用文件；taskPhoto-任务照片 */
    type?: 'file' | 'taskPhoto'
  }>(),
  {
    maxCount: 9,
    tip: '',
    mediaType: () => ['image', 'video'],
    autoUpload: true,
    type: 'file',
  }
)

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

const uploadingSet = ref<Set<string>>(new Set())
const list = computed<string[]>({
  get: () => props.modelValue,
  set: (val: string[]) => emit('update:modelValue', val),
})

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

  chooseMediaCompat({
    count: remainCount,
    mediaType: props.mediaType,
    sourceType: ['album', 'camera'],
    success: async (res) => {
      const tempPaths = res.tempFiles.map((f) => f.tempFilePath)
      list.value = [...list.value, ...tempPaths]
      if (props.autoUpload) {
        const results = await Promise.all(tempPaths.map((path) => uploadOne(path)))
        if (results.every(Boolean)) {
          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)
        : await uploadFile(filePath)

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

function removeMedia(index: number) {
  const next = [...list.value]
  next.splice(index, 1)
  list.value = next
}

function previewMedia(index: number) {
  uni.previewImage({
    urls: list.value,
    current: list.value[index]
  })
}
</script>
