<template>
  <div class="container">
    <van-nav-bar
      title="图片编辑"
      left-arrow
      @click-left="goBack"
      @click-right="onReset"
    >
      <template #left>
        <van-icon name="arrow-left" size="25" />
        <div class="left-btn">返回</div>
      </template>
      <template #right>
        <div class="nav-right right-btn">重置</div>
      </template>
    </van-nav-bar>

    <div class="init-container">
      <div class="workbench-info">
        <p class="info-line">
          仓库：<span class="info-value">{{ workbench.warehouseCode }}</span>
        </p>
        <p class="info-line">
          工作台：<span class="info-value">{{ workbench.workStation }}</span>
        </p>
        <p class="info-line hint-text">支持png/jpeg/jpg/webp/heic/heif（heic/heif自动转webp）</p>
        <van-button
          size="mini"
          type="primary"
          plain
          icon="replay"
          class="refresh-btn"
          @click.stop="getWorkbench"
        ></van-button>
      </div>
      <div class="scan-returned-content">
        <div class="input-group">
          <van-cell title="外箱图上传" />
          <van-uploader
            v-model="outerImages"
            :max-count="5"
            :max-size="15 * 1024 * 1024"
            :before-read="beforeReadImage"
            :preview-full-image="true"
            :deletable="true"
          >
            <template #preview-cover="{ file, index }">
              <div class="custom-cover">
                <!-- 状态指示器 -->
                <div class="upload-status" :class="file.status">
                  <span v-if="file.status === 'uploading'">上传中...</span>
                  <span v-else-if="file.status === 'retrying'">重试中...</span>
                  <span v-else-if="file.status === 'success'">✓ 成功</span>
                  <span v-else-if="file.status === 'failed'">
                    ✗ 失败
                    <van-button
                      v-if="file.retryCount < 1"
                      size="mini"
                      @click.stop="retrySingleImage(file, 'RETURNED_BOX_IMAGE')"
                      style="margin-left: 5px; background: #fff; color: #ee0a24"
                    >
                      重试
                    </van-button>
                    <span v-else style="margin-left: 5px">(已达上限)</span>
                  </span>
                </div>

                <van-button
                  class="cover-button"
                  size="mini"
                  icon="edit"
                  @click.stop="handleOuterImages(file, index)"
                >
                  编辑
                </van-button>
              </div>
            </template>
          </van-uploader>
        </div>

        <div class="input-group">
          <van-cell title="内物图上传" />
          <van-uploader
            v-model="innerImages"
            :max-count="5"
            :max-size="15 * 1024 * 1024"
            :before-read="beforeReadImage"
            :preview-full-image="true"
            :deletable="true"
          >
            <template #preview-cover="{ file, index }">
              <div class="custom-cover">
                <!-- 状态指示器 -->
                <div class="upload-status" :class="file.status">
                  <span v-if="file.status === 'uploading'">上传中...</span>
                  <span v-else-if="file.status === 'retrying'">重试中...</span>
                  <span v-else-if="file.status === 'success'">✓ 成功</span>
                  <span v-else-if="file.status === 'failed'">
                    ✗ 失败
                    <van-button
                      v-if="file.retryCount < 1"
                      size="mini"
                      @click.stop="
                        retrySingleImage(file, 'RETURNED_INNER_IMAGE')
                      "
                      style="margin-left: 5px; background: #fff; color: #ee0a24"
                    >
                      重试
                    </van-button>
                    <span v-else style="margin-left: 5px">(已达上限)</span>
                  </span>
                </div>

                <van-button
                  class="cover-button"
                  size="mini"
                  icon="edit"
                  @click.stop="handleInnerImages(file, index)"
                >
                  编辑
                </van-button>
              </div>
            </template>
          </van-uploader>
        </div>

        <div class="button-group">
          <van-button class="action-btn" type="warning" plain @click="previewAll">预览全部</van-button>
          <van-button class="action-btn action-btn--danger" type="danger" plain @click="onReset">重置图片</van-button>
          <van-button
            class="action-btn"
            type="primary"
            plain
            @click="retryAllFailedImages"
            :disabled="!hasFailedImages()"
          >重传失败图片</van-button>
          <van-button class="action-btn" type="primary" @click="onSubmit">提交</van-button>
        </div>
      </div>
    </div>

    <!-- 自定义图片预览组件 -->
    <van-image-preview
      v-model:show="previewVisible"
      :images="previewImages"
      :start-position="previewStartPosition"
      @change="handlePreviewChange"
    >
      <!-- 自定义操作按钮 -->
      <template #index>
        <div class="preview-toolbar">
          <van-button
            type="primary"
            size="small"
            @click="onEditImage(previewCurrentIndex)"
            :disabled="
              !canEditImage(getPreviewImage(previewCurrentIndex))
            "
          >
            编辑
          </van-button>
        </div>
      </template>
    </van-image-preview>
    <edit-image ref="editImageRef" @save-image="changeFile" />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
// Type declarations for image upload handling
enum UPLOAD_STATUS {
  PENDING = 'pending',
  UPLOADING = 'uploading',
  SUCCESS = 'success',
  FAILED = 'failed',
  RETRYING = 'retrying',
}

interface UploadImage {
  file: File
  status: UPLOAD_STATUS
  url: string | null
  error: string | null
  retryCount: number
  originalFile: File
  // Optional; some flows may carry raw content for previews
  content?: string
}

interface Workbench {
  warehouseCode: string
  workStation: string
}

interface EditImageExposed {
  editImage: (image: UploadImage, type: 'outer' | 'inner') => void
}
import {
  showFailToast,
  showNotify,
  showLoadingToast,
  closeToast,
  showConfirmDialog,
} from 'vant'
import { getHeader, goBack } from '@/utils/android'
import { detailImageUpload, returnedWorkbench } from '@/api/returned/index.ts'
import { compressImage } from '@/utils/imageCompression'
import { convertHeicHeifToWebp, isHeicOrHeif } from '@/utils/imageFormat'
import EditImage from '@/components/EditImage.vue'

const workbench = ref<Workbench>({ warehouseCode: '', workStation: '' })

onMounted(async () => {
  try {
    await getHeader()
  } catch (error: any) {
    if (typeof showFailToast === 'function') {
      showFailToast(error?.message || '获取头信息失败，请稍后重试')
    }
    console.error(error)
  }
  getWorkbench()
})

// 图片上传相关 - 增强数据结构
const outerImages = ref<UploadImage[]>([]) // 外箱图 [{file, status, url, error, retryCount, originalFile}]
const innerImages = ref<UploadImage[]>([]) // 内物图 [{file, status, url, error, retryCount, originalFile}]

// 预览相关变量
const previewVisible = ref<boolean>(false)
const previewImages = ref<string[]>([])
const previewStartPosition = ref<number>(0)
const previewCurrentIndex = ref<number>(0)

// 编辑权限检查
const canEditImage = (imageObj: UploadImage | undefined): boolean => {
  if (!imageObj) return false
  // 只有上传中和重试中的图片不能编辑
  return (
    imageObj.status !== UPLOAD_STATUS.UPLOADING &&
    imageObj.status !== UPLOAD_STATUS.RETRYING
  )
}

// 预览索引变更处理
const handlePreviewChange = (index: number): void => {
  previewCurrentIndex.value = index
}



function getWorkbench(): void {
  returnedWorkbench()
    .then((res) => {
      workbench.value = res.data
    })
    .catch((error: any) => {
      // 记录错误并提示用户，避免静默失败
      console.error('getWorkbench error', error)
      showFailToast('获取工作台信息失败，请稍后重试')
    })
}

const beforeReadImage = async (file: File | File[]): Promise<UploadImage[] | false> => {
  const files = Array.isArray(file) ? file : [file]
  const normalizedFiles: File[] = []

  for (const f of files) {
    const isHeicFile = isHeicOrHeif(f)
    const isImage = /^image\//.test(f.type) || isHeicFile
    if (!isImage) {
      showFailToast('仅支持图片文件')
      return false
    }
    if (f.size > 15 * 1024 * 1024) {
      showFailToast('图片大小不能超过15MB')
      return false
    }

    if (isHeicFile) {
      try {
        const convertedFile = await convertHeicHeifToWebp(f)
        normalizedFiles.push(convertedFile)
      } catch (error) {
        console.error('HEIC/HEIF 转换失败:', error)
        showFailToast('HEIC/HEIF 转换失败，请使用 JPG/PNG/WEBP 格式')
        return false
      }
      continue
    }

    normalizedFiles.push(f)
  }

  // 返回增强的图片对象数组，包含状态信息
  return normalizedFiles.map((f) => ({
    file: f, // 原始File对象
    status: UPLOAD_STATUS.PENDING,
    url: null,
    error: null,
    retryCount: 0,
    originalFile: f, // 保留用于重传
  }))
}

// 单张图片上传函数
const uploadSingleImage = async (
  imageObj: UploadImage,
  category: string,
): Promise<boolean> => {
  imageObj.status = UPLOAD_STATUS.UPLOADING

  try {
    const compressedFile = await compressImage(imageObj.file, 0.5)
    const data = new FormData()
    data.set('file', compressedFile)
    data.set('type', category)
    // detailImageUpload成功执行即成功，catch到异常即失败
    await detailImageUpload(data)

    imageObj.status = UPLOAD_STATUS.SUCCESS
    imageObj.url = URL.createObjectURL(imageObj.file)
    imageObj.error = null
    return true
  } catch (error) {
    // 标记失败并记录错误，但不要将内部错误信息暴露给用户
    imageObj.status = UPLOAD_STATUS.FAILED
    imageObj.error = '上传失败，请稍后再试'
    // retryCount 不在此处修改，由重试调用方负责递增
    // 记录详细错误以供调试
    console.error('uploadSingleImage error', error)
    return false
  }
}

const uploadCategoryWithStatus = async (
  list: UploadImage[],
  categoryName: string,
): Promise<{ success: boolean; item: UploadImage }[]> => {
  const results: { success: boolean; item: UploadImage }[] = []

  for (const item of list) {
    // 跳过已成功的图片
    if (item.status === UPLOAD_STATUS.SUCCESS) {
      results.push({ success: true, item })
      continue
    }
    console.log(item,categoryName)
    const success = await uploadSingleImage(item, categoryName)
    results.push({ success, item })
  }

  return results
}

// 获取预览图片对象
const getPreviewImage = (index: number): UploadImage => {
  const allImages = [...outerImages.value, ...innerImages.value]
  return allImages[index] as UploadImage
}

const onEditImage = (index: number): void => {
  // 获取图片对象
  const imageObj = getPreviewImage(index)

  if (!imageObj) return

  // 检查是否可以编辑
  if (!canEditImage(imageObj)) {
    showNotify({
      type: 'warning',
      message: '图片正在上传中，请稍后再编辑',
    })
    return
  }

  // 关闭预览
  previewVisible.value = false

  // 确定图片类型和索引
  let type: 'outer' | 'inner'
  if (index < outerImages.value.length) {
    // 是外箱图
    type = 'outer'
    outerImagesIndex.value = index
  } else {
    // 是内物图
    type = 'inner'
    innerImagesIndex.value = index - outerImages.value.length
  }

  // 打开编辑界面
  setTimeout(() => {
    editImageRef.value?.editImage(imageObj, type)
  }, 300)
}

const previewAll = (): void => {
  const images = [...outerImages.value, ...innerImages.value]
    .map(
      (it) => it.url || (it.file ? URL.createObjectURL(it.file) : it.content),
    )
    .filter(Boolean)
  if (!images.length) {
    showNotify({ type: 'warning', message: '暂无可预览的图片' })
    return
  }
  previewImages.value = images
  previewStartPosition.value = 0
  previewCurrentIndex.value = 0
  previewVisible.value = true
}

const onReset = (): void => {
  outerImages.value = []
  innerImages.value = []
  showNotify({ type: 'primary', message: '已重置图片' })
}

const onSubmit = async (): Promise<void> => {
  if (!outerImages.value.length && !innerImages.value.length) {
    showFailToast('请先上传外箱图或内物图')
    return
  }
  try {
    const outerCount = outerImages.value.length
    const innerCount = innerImages.value.length
    await showConfirmDialog({
      title: '确认提交',
      message: `外箱图：${outerCount} 张\n内物图：${innerCount} 张\n是否确认提交？`,
    })
  } catch (e) {
    showNotify({ type: 'warning', message: '已取消提交' })
    return
  }

  const toast = showLoadingToast({ duration: 0, message: '上传中...' })
  try {
    // 使用新的上传函数
    const outerResults = await uploadCategoryWithStatus(
      outerImages.value,
      'RETURNED_BOX_IMAGE',
    )
    const innerResults = await uploadCategoryWithStatus(
      innerImages.value,
      'RETURNED_INNER_IMAGE',
    )

    closeToast()

    // 统计结果
    const allResults = [...outerResults, ...innerResults]
    const successCount = allResults.filter((r) => r.success).length
    const failedCount = allResults.filter((r) => !r.success).length

    if (failedCount === 0) {
      // 全部成功：清空所有图片
      showNotify({ type: 'success', message: '提交成功' })
      outerImages.value = []
      innerImages.value = []
    } else {
      // 有失败图片：只清空成功的，保留失败的
      showNotify({
        type: 'warning',
        duration: 5000,
        message: `上传完成，成功 ${successCount} 张，失败 ${failedCount} 张。失败图片已保留，可手动重传。`,
      })

      // 只清空成功的图片
      outerImages.value = outerImages.value.filter(
        (img) => img.status !== UPLOAD_STATUS.SUCCESS,
      )
      innerImages.value = innerImages.value.filter(
        (img) => img.status !== UPLOAD_STATUS.SUCCESS,
      )
    }
  } catch (error) {
    // 保证用户看到的错误信息不包含内部实现细节
    closeToast()
    console.error('onSubmit error', error)
    showFailToast('提交失败，请稍后再试')
  }
}

// 手动重传相关函数
// 单张图片重传
const retrySingleImage = async (
  imageObj: UploadImage,
  category: string,
): Promise<void> => {
  // 检查重传次数
  if (imageObj.retryCount >= 1) {
    showNotify({ type: 'warning', message: '已达到最大重传次数' })
    return
  }

  imageObj.status = UPLOAD_STATUS.RETRYING
  const success = await uploadSingleImage(imageObj, category)
  imageObj.retryCount++ // 无论成功失败，重试次数+1

  if (success) {
    showNotify({ type: 'success', message: '重传成功' })
    // 成功后会从列表中移除（在下次提交时）
  } else {
    showNotify({
      type: 'danger',
      message: `重传失败`,
    })
  }
}

// 批量重传失败图片
const retryAllFailedImages = async (): Promise<void> => {
  const allImages = [...outerImages.value, ...innerImages.value]
  const failedImages = allImages.filter(
    (img) => img.status === UPLOAD_STATUS.FAILED && img.retryCount < 1,
  )

  if (failedImages.length === 0) {
    showNotify({ type: 'primary', message: '没有需要重传的图片' })
    return
  }

  const toast = showLoadingToast({
    duration: 0,
    message: `重传 ${failedImages.length} 张图片...`,
  })

  let successCount = 0
  for (const img of failedImages) {
    const category = outerImages.value.includes(img)
      ? 'RETURNED_BOX_IMAGE'
      : 'RETURNED_INNER_IMAGE'
    const success = await uploadSingleImage(img, category)
    img.retryCount++ // 无论成功失败，重试次数+1
    if (success) successCount++
  }

  closeToast()
  showNotify({
    type: successCount === failedImages.length ? 'success' : 'warning',
    message: `重传完成，成功 ${successCount}/${failedImages.length} 张`,
  })
}

// 计算是否有失败图片
const hasFailedImages = (): boolean => {
  const allImages = [
    ...outerImages.value,
    ...innerImages.value,
  ] as UploadImage[]
  return allImages.some(
    (img: UploadImage) =>
      img.status === UPLOAD_STATUS.FAILED && img.retryCount < 1,
  )
}

// 外箱图
const outerImagesIndex = ref<number>(-1)
// 内物图
const innerImagesIndex = ref<number>(-1)
const editImageRef = ref<EditImageExposed | null>(null)

/**
 * 处理图片编辑操作
 * @param file 文件对象
 * @param index 文件下标
 */
const handleInnerImages = (_slotFile: unknown, index: number): void => {
  // 直接从响应式列表取原始对象，避免 Vant 插槽包装层导致 file 字段异常
  const imageObj = innerImages.value[index]
  if (!imageObj) return

  if (!canEditImage(imageObj)) {
    showNotify({
      type: 'warning',
      message: '图片正在上传中，请稍后再编辑',
    })
    return
  }

  // 保证传入 EditImage 时有可用的预览 URL
  if (!imageObj.url && !imageObj.content && imageObj.file instanceof File) {
    imageObj.content = URL.createObjectURL(imageObj.file)
  }

  innerImagesIndex.value = index
  editImageRef.value?.editImage(imageObj, 'inner')
}

/**
 * 处理图片编辑操作
 * @param _slotFile 插槽传来的对象（Vant 包装层，不可靠，弃用）
 * @param index 文件下标
 */
const handleOuterImages = (_slotFile: unknown, index: number): void => {
  // 直接从响应式列表取原始对象，避免 Vant 插槽包装层导致 file 字段异常
  const imageObj = outerImages.value[index]
  if (!imageObj) return

  if (!canEditImage(imageObj)) {
    showNotify({
      type: 'warning',
      message: '图片正在上传中，请稍后再编辑',
    })
    return
  }

  // 保证传入 EditImage 时有可用的预览 URL
  if (!imageObj.url && !imageObj.content && imageObj.file instanceof File) {
    imageObj.content = URL.createObjectURL(imageObj.file)
  }

  outerImagesIndex.value = index
  editImageRef.value?.editImage(imageObj, 'outer')
}

const changeFile = async (
  editedDataURL: string,
  type: 'inner' | 'outer',
): Promise<void> => {
  try {
    // 根据type找到对应的图片索引和列表
    const index =
      type === 'inner' ? innerImagesIndex.value : outerImagesIndex.value
    const imageList = type === 'inner' ? innerImages.value : outerImages.value

    if (index === -1 || !imageList[index]) {
      showNotify({ type: 'warning', message: '未找到对应的图片' })
      return
    }

    const imageObj = imageList[index]

    // 将base64转换为File对象
    const editedFile = dataURLtoFile(
      editedDataURL,
      getFileNameByMime(imageObj.file.name, editedDataURL),
    )

    // 压缩图片（EditImage保存的是PNG，可能很大）
    const compressedFile = await compressImage(editedFile)

    // 释放旧的预览URL（内存管理）
    if (imageObj.url && imageObj.url.startsWith('blob:')) {
      URL.revokeObjectURL(imageObj.url)
    }

    // 只更新文件内容和预览URL
    imageObj.file = compressedFile
    imageObj.originalFile = compressedFile
    imageObj.url = editedDataURL // 使用原始的base64作为预览（质量更好）

    // 若图片已成功上传，编辑后需重置为 PENDING，确保提交时重新上传编辑后的版本
    if (imageObj.status === UPLOAD_STATUS.SUCCESS) {
      imageObj.status = UPLOAD_STATUS.PENDING
      imageObj.error = null
    }
    // 其余状态（PENDING / FAILED）保持不变，由正常上传流程处理

    showNotify({ type: 'success', message: '图片编辑完成' })
  } catch (error) {
    console.error('图片编辑保存失败:', error)
    showNotify({
      type: 'danger',
      message: '图片编辑保存失败，请重试',
    })
  }
}

// base64转File函数
function dataURLtoFile(dataurl: string, filename: string): File {
  const arr = dataurl.split(',')
  const mimeMatch = arr[0].match(/:(.*?);/)
  if (!mimeMatch) throw new Error('无效的 dataURL 格式')
  const mime = mimeMatch[1]
  const bstr = atob(arr[1])
  let n = bstr.length
  const u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], filename, { type: mime })
}

function getFileNameByMime(fileName: string, dataUrl: string): string {
  const mimeMatch = dataUrl.match(/^data:(.*?);/)
  const mime = mimeMatch?.[1] || ''
  const ext = mime.split('/')[1]
  if (!ext) return fileName

  const normalizedExt = ext.split('+')[0].toLowerCase()
  const dotIndex = fileName.lastIndexOf('.')
  if (dotIndex <= 0) return `${fileName}.${normalizedExt}`
  return `${fileName.slice(0, dotIndex)}.${normalizedExt}`
}
</script>

<style scoped lang="sass">
.van-nav-bar
  .left-btn
    color: #fff
    height: 46px
    padding-right: 20px
    line-height: 46px

  .right-btn
    color: #fff

// ── 仓库信息区 ──
.workbench-info
  background: #fff
  padding: 10px 14px 8px
  border-bottom: 1px solid #f0f0f0

  .info-line
    margin: 0 0 4px
    font-size: 14px
    color: #666

  .info-value
    color: #1989fa
    font-weight: 500

  .hint-text
    color: #999
    font-size: 12px

  .refresh-btn
    margin-top: 4px

// ── 主内容区 ──
.container
  .init-container
    width: 100%

    .scan-returned-content
      padding: 10px

      .input-group
        padding: 5px

      .button-group
        display: flex
        gap: 8px
        padding: 8px 5px
        flex-wrap: wrap

        .action-btn
          flex: 1
          min-width: 70px
          height: 38px
          font-size: 13px
          border-radius: 8px

  .content
    width: 100%

  .scan-returned-no
    align-items: center
    padding: 15px

  .returned-detail-list
    .card-div
      background: #fff
      border-radius: 12px
      overflow: hidden
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05)
      margin: 5px 0
      padding: 5px 0

      .card-div-content
        padding: 3px

        .info-row
          display: flex
          margin-bottom: 12px
          font-size: 12px

// 图片预览工具栏样式
.preview-toolbar
  display: flex
  justify-content: flex-end
  margin-top: 10px
  padding: 0 15px

  .van-button
    margin-left: 10px

.custom-cover
  position: absolute
  top: 0
  left: 0
  box-sizing: border-box
  width: 100%
  height: 100%
  display: flex
  align-items: flex-end
  /* 按钮通常放在底部 */
  justify-content: center
  padding: 8px
  /* 留出边距 */
  background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent)
  /* 可选：底部渐变背景，让按钮更清晰 */
  pointer-events: none
/* 关键：避免覆盖层拦截图片的点击预览事件 */

.cover-button
  pointer-events: auto
/* 关键：允许按钮本身接收点击事件 */

// 上传状态样式
.upload-status
  position: absolute
  top: 5px
  left: 5px
  padding: 2px 6px
  border-radius: 3px
  font-size: 12px
  color: white
  background-color: rgba(0, 0, 0, 0.7)

.upload-status.success
  background-color: #07c160

.upload-status.failed
  background-color: #ee0a24

.upload-status.uploading
  background-color: #1989fa

.upload-status.retrying
  background-color: #ff976a

.upload-status.pending
  background-color: #969799
</style>
