import type { UploadCustomRequestOptions } from 'naive-ui'
import type { Region, TemplateInfo } from '../types'
import * as pdfjsLib from 'pdfjs-dist'
import { onMounted, ref, type Ref } from 'vue'
import { getAliOssTokenAxios } from '@/service/api/upload'
import { browserPathJoin } from '@/utils/date'
import { initOSSClient, uploadFileToOSS } from '@/utils/oss'

export function useUpload(
  imgSrc: Ref<string>,
  templateInfo: Ref<TemplateInfo>,
  regions: Ref<Region[]>,
  selectedRegionIds: Ref<Set<string>>,
) {
  const loading = ref(false)

  onMounted(() => {
    pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
      'pdfjs-dist/build/pdf.worker.min.mjs',
      import.meta.url,
    ).toString()
  })

  /**
   * 渲染 PDF 页面
   */
  async function renderPdfPage(file: File): Promise<{ url: string, width: number, height: number, blob: Blob }> {
    const arrayBuffer = await file.arrayBuffer()
    const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise
    const page = await pdf.getPage(1)

    // 这里的 scale 决定了分辨率。A4 @ 72dpi ~= 595x842.
    // 2100 / 595 ~= 3.5.
    const viewportBase = page.getViewport({ scale: 1 })
    const scale = 2100 / viewportBase.width
    const viewport = page.getViewport({ scale })

    const canvas = document.createElement('canvas')
    const context = canvas.getContext('2d')

    if (!context) {
      throw new Error('Canvas context not found')
    }

    canvas.width = viewport.width
    canvas.height = viewport.height

    await page.render({
      canvasContext: context,
      viewport,
      canvas,
    }).promise

    return new Promise((resolve, reject) => {
      canvas.toBlob((blob) => {
        if (blob) {
          resolve({
            url: URL.createObjectURL(blob),
            width: viewport.width,
            height: viewport.height,
            blob,
          })
        }
        else {
          reject(new Error('Canvas to Blob failed'))
        }
      }, 'image/jpeg', 0.8)
    })
  }

  /**
   * 上传文件到 OSS
   */
  async function uploadToOSS(file: File | Blob, fileName: string): Promise<string> {
    const { data: tokenData, error: tokenError } = await getAliOssTokenAxios()
    if (tokenError || !tokenData) {
      throw new Error('获取上传凭证失败')
    }

    // 初始化OSS客户端
    const client = initOSSClient(tokenData.data)
    const path = browserPathJoin(`temp/${Date.now()}`, fileName)

    // 上传文件
    await uploadFileToOSS(client, file as any, path)

    return browserPathJoin(import.meta.env.VITE_BASE_OSS_URL, path)
  }

  /**
   * 触发上传前的检查
   * @param openFileDialog 打开文件选择器的回调
   */
  function handleUploadCheck(openFileDialog: () => void) {
    if (imgSrc.value) {
      window?.$dialog?.warning({
        title: '确认更换',
        content: '更换底图将清空当前已生成的布局，是否继续？',
        positiveText: '确定',
        negativeText: '取消',
        onPositiveClick: () => {
          openFileDialog()
        },
      })
    }
    else {
      openFileDialog()
    }
  }

  /**
   * 处理上传
   */
  function handleUpload(options: UploadCustomRequestOptions) {
    const { file, onFinish, onError } = options

    const processFile = async () => {
      loading.value = true
      try {
        const currentFile = file.file as File
        let width = 0
        let height = 0
        let fileToUpload: File | Blob = currentFile
        let uploadFileName = currentFile.name

        if (file.type === 'application/pdf') {
          const result = await renderPdfPage(currentFile)
          width = result.width
          height = result.height
          fileToUpload = result.blob
          uploadFileName = currentFile.name.replace('.pdf', '.jpg')
        }
        else {
          // Image
          await new Promise<void>((resolve, reject) => {
            const reader = new FileReader()
            reader.readAsDataURL(currentFile)
            reader.onload = () => {
              const url = reader.result as string
              const img = new Image()
              img.onload = () => {
                width = img.width
                height = img.height
                resolve()
              }
              img.onerror = reject
              img.src = url
            }
            reader.onerror = reject
          })
        }

        // 上传到 OSS
        const ossUrl = await uploadToOSS(fileToUpload, uploadFileName)

        // 更新状态
        imgSrc.value = ossUrl
        templateInfo.value.width = Math.round(width)
        templateInfo.value.height = Math.round(height)
        templateInfo.value.backGroundUrl = ossUrl

        // Clear regions
        regions.value = []
        selectedRegionIds.value.clear()

        onFinish()
        window?.$message?.success('上传成功')
      }
      catch (e) {
        console.error(e)
        onError()
        window?.$message?.error('文件处理失败')
      }
      finally {
        loading.value = false
      }
    }

    processFile()
  }

  return {
    loading,
    handleUpload,
    handleUploadCheck,
  }
}
