import { t } from '@/i18n'
import { useToastStore } from '@/platform/updates/common/toastStore'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'

class Load3dUtils {
  static async uploadTempImage(
    imageData: string,
    prefix: string,
    fileType: string = 'png'
  ) {
    const blob = await fetch(imageData).then((r) => r.blob())
    const name = `${prefix}_${Date.now()}.${fileType}`
    const file = new File([blob], name, {
      type: fileType === 'mp4' ? 'video/mp4' : 'image/png'
    })

    const body = new FormData()
    body.append('image', file)
    body.append('subfolder', 'threed')
    body.append('type', 'temp')

    const resp = await api.fetchApi('/upload/image', {
      method: 'POST',
      body
    })

    if (resp.status !== 200) {
      const err = `Error uploading temp file: ${resp.status} - ${resp.statusText}`
      useToastStore().addAlert(err)
      throw new Error(err)
    }

    return await resp.json()
  }

  static readonly MAX_UPLOAD_SIZE_MB = 100

  static async uploadFile(file: File, subfolder: string) {
    let uploadPath

    const fileSizeMB = file.size / 1024 / 1024
    if (fileSizeMB > this.MAX_UPLOAD_SIZE_MB) {
      const message = t('toastMessages.fileTooLarge', {
        size: fileSizeMB.toFixed(1),
        maxSize: this.MAX_UPLOAD_SIZE_MB
      })
      console.warn(
        '[Load3D] uploadFile: file too large',
        fileSizeMB.toFixed(2),
        'MB'
      )
      useToastStore().addAlert(message)
      return undefined
    }

    try {
      const body = new FormData()
      body.append('image', file)

      body.append('subfolder', subfolder)

      const resp = await api.fetchApi('/upload/image', {
        method: 'POST',
        body
      })

      if (resp.status === 200) {
        const data = await resp.json()
        let path = data.name

        if (data.subfolder) {
          path = data.subfolder + '/' + path
        }

        uploadPath = path
      } else {
        useToastStore().addAlert(resp.status + ' - ' + resp.statusText)
      }
    } catch (error) {
      console.error('[Load3D] uploadFile: exception', error)
      useToastStore().addAlert(
        error instanceof Error
          ? error.message
          : t('toastMessages.fileUploadFailed')
      )
    }

    return uploadPath
  }

  static getFilenameExtension(url: string): string | undefined {
    const queryString = url.split('?')[1]
    if (queryString) {
      const filename = new URLSearchParams(queryString).get('filename')
      if (filename) return filename.split('.').pop()?.toLowerCase()
    }
    return url.split('?')[0].split('.').pop()?.toLowerCase()
  }

  static splitFilePath(path: string): [string, string] {
    const folder_separator = path.lastIndexOf('/')
    if (folder_separator === -1) {
      return ['', path]
    }
    return [
      path.substring(0, folder_separator),
      path.substring(folder_separator + 1)
    ]
  }

  static getResourceURL(
    subfolder: string,
    filename: string,
    type: string = 'input'
  ): string {
    const params = [
      'filename=' + encodeURIComponent(filename),
      'type=' + type,
      'subfolder=' + subfolder,
      app.getRandParam().substring(1)
    ].join('&')

    return `/view?${params}`
  }

  static async uploadMultipleFiles(files: FileList, subfolder: string = '3d') {
    const uploadPromises = Array.from(files).map((file) =>
      this.uploadFile(file, subfolder)
    )

    await Promise.all(uploadPromises)
  }

  static mapSceneLightIntensityToHdri(
    sceneIntensity: number,
    sceneMin: number,
    sceneMax: number
  ): number {
    const span = sceneMax - sceneMin
    const t = span > 0 ? (sceneIntensity - sceneMin) / span : 0
    const clampedT = Math.min(1, Math.max(0, t))
    const mapped = clampedT * 5
    const minHdri = 0.25
    return Math.min(5, Math.max(minHdri, mapped))
  }
}

export default Load3dUtils
