const ALLOWED_IMAGE_TYPES = new Set([
  'image/jpeg',
  'image/jpg',
  'image/png',
  'image/webp',
  'image/gif',
])

function parseDataUrl(dataUrl: string): { mime: string; bytes: Uint8Array } {
  const match = dataUrl.match(/^data:([^;]+);base64,(.+)$/)
  if (!match) {
    throw new Error('Invalid image data')
  }

  const mime = match[1] === 'image/jpg' ? 'image/jpeg' : match[1]
  const binary = atob(match[2])
  const bytes = new Uint8Array(binary.length)
  for (let i = 0; i < binary.length; i += 1) {
    bytes[i] = binary.charCodeAt(i)
  }

  return { mime, bytes }
}

function loadImage(src: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const image = new Image()
    image.addEventListener('load', () => resolve(image))
    image.addEventListener('error', () => reject(new Error('Could not load image')))
    image.src = src
  })
}

export function dataUrlToFile(dataUrl: string, filename: string): File {
  const { mime, bytes } = parseDataUrl(dataUrl)
  const copy = new Uint8Array(bytes)
  return new File([copy], filename, { type: mime })
}

export async function ensureUploadFile(dataUrl: string, filename: string): Promise<File> {
  if (dataUrl.startsWith('data:')) {
    const mime = dataUrl.slice(5, dataUrl.indexOf(';'))
    const normalized = mime === 'image/jpg' ? 'image/jpeg' : mime

    if (ALLOWED_IMAGE_TYPES.has(normalized)) {
      const file = dataUrlToFile(dataUrl, filename)
      if (file.size > 0) {
        return file
      }
    }
  }

  const image = await loadImage(dataUrl)
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  if (!ctx) {
    throw new Error('Could not prepare image for upload')
  }

  const wantsPng = filename.toLowerCase().endsWith('.png')
  canvas.width = image.naturalWidth
  canvas.height = image.naturalHeight

  if (wantsPng) {
    ctx.clearRect(0, 0, canvas.width, canvas.height)
  }

  ctx.drawImage(image, 0, 0)

  const outputDataUrl = wantsPng
    ? canvas.toDataURL('image/png')
    : canvas.toDataURL('image/jpeg', 0.92)
  const safeName = filename.replace(/\.[^.]+$/, '') || 'image'
  const extension = wantsPng ? 'png' : 'jpg'
  return dataUrlToFile(outputDataUrl, `${safeName}.${extension}`)
}

export async function ensureJpegUploadFile(
  dataUrl: string,
  filename: string,
): Promise<File> {
  return ensureUploadFile(
    dataUrl,
    filename.toLowerCase().endsWith('.jpg') || filename.toLowerCase().endsWith('.jpeg')
      ? filename
      : `${filename.replace(/\.[^.]+$/, '') || 'image'}.jpg`,
  )
}
