/* eslint-disable no-console */
import { snapdom } from '@zumer/snapdom'
import { getTrueRandomInt } from './date'
import { getSnowflake } from './rest'

/** 通过 url 判断是否为 图片链接 */
export function isImageUrl(url: string) {
  const str = url.split('?')[0]!.substring(url.lastIndexOf('.') + 1) || ''
  return ['jpg', 'jpeg', 'png', 'webp', 'svg', 'gif'].includes(str.toLocaleLowerCase())
}

/** 通过 url 判断是否为 图片链接 */
export function isVideoUrl(url: string) {
  const str = url.split('?')[0]!.substring(url.lastIndexOf('.') + 1) || ''
  return ['m4v', 'mov', '3gp', '3g2', 'mp4', 'flv', 'f4v', 'webm', 'wmv', 'avi', 'asf'].includes(str.toLocaleLowerCase())
}

/** 得到 */
export function getAssetsFile(url: string) {
  return new URL(url, import.meta.url).href
}

/**
 * 打开文件选择器并返回用户选择的文件
 * @param accept 文件类型过滤（如 "image/*"、"application/pdf"）
 * @param multiple 是否支持多选（默认 false）
 * @returns Promise<File[]> 返回 File 对象数组
 */
export function selectFiles(accept = '*/*', multiple = false): Promise<File[]> {
  return new Promise((resolve, reject) => {
    // 1. 创建隐藏的文件输入元素
    const input = document.createElement('input')
    input.type = 'file'
    input.accept = accept
    input.multiple = multiple
    input.style.display = 'none'

    // 2. 监听文件选择事件
    input.addEventListener('change', () => {
      if (!input.files || input.files.length === 0) {
        reject(new Error('未选择文件'))
        return
      }

      // 3. 转换为 File 对象数组
      const files = Array.from(input.files)
      resolve(files)

      // 4. 清理DOM
      document.body.removeChild(input)
    })

    // 5. 触发文件选择弹窗
    document.body.appendChild(input)
    input.click()
  })
}

/**
 * Base64字符串转换为File对象
 * @param dataUrl Base64字符串
 * @param filename 文件名
 * @returns File对象
 */
export function base64ToFile(dataUrl: string, filename: string): File {
  // 拆分 Data URL
  const arr = dataUrl.split(',')
  const mimeMatch = arr[0]?.match(/:(.*?);/) || null
  if (!mimeMatch || !mimeMatch[1] || !arr[1]) {
    throw new Error('无效的Base64字符串')
  }
  const mime = mimeMatch[1] // 提取 MIME 类型（如 "image/png"）
  const bstr = atob(arr[1]) // Base64 解码
  const n = bstr.length
  const u8arr = new Uint8Array(n)

  // 将解码后的二进制数据存入 Uint8Array
  for (let i = 0; i < n; i++) {
    u8arr[i] = bstr.charCodeAt(i)
  }

  // 生成 File 对象
  return new File([u8arr], filename, { type: mime })
}

/**
 * 将图片file转换为Base64对象
 */
export function fileToBase64(file: File): Promise<{ id: string, img: string }> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = (e) => {
      const date = new Date().getTime()
      const num = getTrueRandomInt(100000000, 99999999999)
      if (file.size > 1024 * 40) {
        // 只有大于40kb才压缩
        const img = new Image()
        img.src = String(e.target?.result || '')
        img.onload = async () => {
          const Base64Url = await compressImg(img, file.type)
          resolve({ id: `id_${date}_${num}`, img: Base64Url })
        }
        img.onerror = () => {
          reject(new Error('加载图片失败,002'))
        }
      }
      else {
        resolve({ id: `id_${date}_${num}`, img: String(e.target?.result || '') })
      }
    }
    reader.onerror = () => {
      reject(new Error('加载图片失败,001'))
    }
  })
}

/**
 * 压缩图片
 * @param img - 被压缩的img对象
 * @param imgType - 图片类型
 * @param mx - 触发压缩的图片最大宽度限制
 * @param mh - 触发压缩的图片最大高度限制
 * @param quality - 清晰度 0到1之间
 */
export function compressImg(img: HTMLImageElement, imgType = 'image/jpeg', mx = 720, mh = 1280, quality = 0.8): Promise<string> {
  return new Promise((resolve) => {
    const canvas = document.createElement('canvas')
    const context = canvas.getContext('2d')
    const { width: originWidth, height: originHeight } = img
    // 最大尺寸限制
    const maxWidth = mx
    const maxHeight = mh
    // 目标尺寸
    let targetWidth = originWidth
    let targetHeight = originHeight
    if (originWidth > maxWidth || originHeight > maxHeight) {
      if (originWidth / originHeight > 1) {
        // 宽图片
        targetWidth = maxWidth
        targetHeight = Math.round(maxWidth * (originHeight / originWidth))
      }
      else {
        // 高图片
        targetHeight = maxHeight
        targetWidth = Math.round(maxHeight * (originWidth / originHeight))
      }
    }
    canvas.width = targetWidth
    canvas.height = targetHeight
    if (context) {
      context.clearRect(0, 0, targetWidth, targetHeight)
      // 图片绘制
      context.drawImage(img, 0, 0, targetWidth, targetHeight)
    }
    const dataURL = canvas.toDataURL(imgType, quality) // 转换图片为dataURL
    // const fun = (blob) => {
    //    resolve(blob);
    // };
    // 转换为bolb对象
    // canvas.toBlob(fun, imgType, 0.7);
    resolve(dataURL)
  })
}

/**
 * 获取视频第一帧
 * @param videoSource - 视频源，可以是URL或Blob
 * @returns - 第一帧的File对象
 */
export function getFirstFrameOfVideo(
  videoSource: Blob | File | string,
): Promise<{ firstFrame: File, duration: number, videoWidth: number, videoHeight: number }> {
  return new Promise((resolve, reject) => {
    let url = '' // 使用createObjectURL创建的URL

    // 创建视频元素
    const video = document.createElement('video')
    video.crossOrigin = 'Anonymous'
    video.setAttribute('playsinline', '')
    video.muted = true

    // 事件监听：当视频可播放时处理
    video.addEventListener('seeked', () => {
      const canvas = document.createElement('canvas')
      canvas.width = video.videoWidth
      canvas.height = video.videoHeight

      const context = canvas.getContext('2d')
      if (context) {
        context.drawImage(video, 0, 0, canvas.width, canvas.height)
        const blobCallback = (blob: Blob | null) => {
          if (blob) {
            const name = `${getSnowflake()}_${Math.random().toString(32).substring(2)}.png`
            // 将 Blob 转换为 File
            const firstFrame = new File([blob], name, { type: blob.type })
            resolve({ firstFrame, videoWidth: video.videoWidth, videoHeight: video.videoHeight, duration: video.duration })
            url && URL.revokeObjectURL(url) // 使用createObjectURL创建的URL应在不再需要时通过revokeObjectURL释放，以避免内存泄漏。
          }
          else {
            reject(new Error('获取地一帧失败,BD002'))
          }
        }
        canvas.toBlob(blobCallback, 'image/jpeg', 0.7)
      }
      else {
        reject(new Error('获取地一帧失败,BD001'))
      }
    })

    // 错误处理
    video.addEventListener('error', () => {
      reject(new Error('获取地一帧失败,BD003'))
    })

    // 设置视频源
    if (videoSource instanceof Blob || (videoSource as any) instanceof File) {
      // Blob 或 File
      url = URL.createObjectURL(videoSource as Blob | File)
      video.src = url
      video.load()
    }
    else if (typeof videoSource === 'string') {
      video.src = videoSource
      video.load()
    }
    else {
      reject(new Error('不支持此类型'))
    }
    video.currentTime = 0.01
  })
}

/**
 * 得到图片的宽高
 * @param file - 图片,可以是 url 或者File
 */
export function getImageWidthHeight(file: Blob | File | string): Promise<{ width: number, height: number }> {
  return new Promise<{ width: number, height: number }>((resolve, reject) => {
    const img = new Image()
    img.onload = () => {
      const size = { width: img.width, height: img.height }
      resolve(size)
    }
    img.onerror = () => {
      reject(new Error('读取图片失败,BD0001'))
    }

    if (typeof file === 'string') {
      img.src = file
    }
    else if (file instanceof File || file instanceof Blob) {
      img.src = URL.createObjectURL(file)
    }
    else {
      reject(new Error('读取图片失败,BD0002'))
    }
  })
}

/**
 * html 转换为 jpg图片
 */
export async function htmlToJpgImgFile(html: string, op: { width: number }): Promise<File> {
  const type: 'jpeg' | 'jpg' | 'png' | 'svg' | 'webp' = 'jpg'
  // 创建临时容器
  const container = document.createElement('div')
  container.style.width = `${op.width}px`
  container.style.position = 'absolute'
  container.style.left = '101vw'
  container.style.top = '101vh'
  container.style.zIndex = '-1'
  container.style.backgroundColor = '#ffffff'
  container.innerHTML = html
  document.body.appendChild(container)
  try {
    // 等待图片加载完成
    const images = container.querySelectorAll('img')
    const imageLoadPromises = Array.from(images).map((img) => {
      if (img.complete) {
        return Promise.resolve()
      }
      return new Promise((resolve) => {
        img.onload = () => resolve(null)
        img.onerror = () => resolve(null) // 即使图片加载失败也继续
        // 设置超时，防止某些图片一直加载不成功
        setTimeout(() => resolve(null), 5000)
      })
    })

    await Promise.all(imageLoadPromises)
    console.log('所有图片加载完成，图片数量:', images.length)

    // 额外等待确保DOM完全渲染
    await new Promise((resolve) => {
      setTimeout(() => {
        requestAnimationFrame(resolve)
      }, 100) // 增加等待时间
    })

    const name = `${getSnowflake()}_${Math.random().toString(32).substring(2)}.jpg`
    console.log('开始截图，容器宽度:', container.offsetWidth, '高度:', container.offsetHeight)

    // 使用 snapdom 进行 DOM 快照
    const res = await snapdom(container, {
      width: op.width,
      scale: 1,
      type,
      backgroundColor: '#ffffff',
    })

    const blob = await res.toBlob({ type, backgroundColor: '#ffffff' })

    console.log('截图完成，blob大小:', (blob.size / 1024).toFixed(2), 'KB')

    // 将blob转换为base64以便在浏览器查看
    const reader = new FileReader()
    const base64Promise = new Promise<string>((resolve) => {
      reader.onloadend = () => {
        resolve(reader.result as string)
      }
      reader.readAsDataURL(blob)
    })
    // eslint-disable-next-line unused-imports/no-unused-vars
    const base64 = await base64Promise
    // console.log("blob=====", blob);
    // console.log("图片base64=====", base64);
    // console.log("👆 复制上面的base64到浏览器地址栏查看图片");

    return new File([blob], name, { type: blob.type })
  }
  catch (error) {
    console.error('htmlToJpgImgFile 错误:', error)
    return Promise.reject(error)
  }
  finally {
    //  document.body.removeChild(container);
  }
}
