/* eslint-disable */
// @ts-ignore

import { FileLoader, Texture, type WebGLRenderer } from "three";
import {
  type GLTF,
  GLTFLoader,
} from "three/examples/jsm/loaders/GLTFLoader.js";

import type { AssetsData } from "@/types";

class AssetsType {
  static VIDEO = "video";
  static IMAGE = "image";
  static FONT = "font";
  static TEXTURE = "texture";
  static GLTF = "gltf";
  static AUDIO = "audio";
}

class AssetsProvider {
  static assets: { [id: string]: AssetsData } = {};
  static loadingProgress = 0;
  static gltfLoader = new GLTFLoader();
  static audioLoader = new FileLoader();

  static async loadAssets(
    assetsData: Array<AssetsData>,
    callBackProgress: Function,
    renderer?: WebGLRenderer,
  ): Promise<number> {
    let loadedObjects = 0;

    for (let i: number = 0; i < assetsData.length; i++) {
      const ad = assetsData[i] as any;
      let asset;
      switch (ad.type) {
        case AssetsType.IMAGE:
          asset = await AssetsProvider.loadImage(ad.path);
          break;
        case AssetsType.VIDEO:
          asset = await AssetsProvider.loadVideo(ad.path);
          break;
        case AssetsType.TEXTURE:
          const img = await AssetsProvider.loadImage(ad.path);
          asset = new Texture();
          asset.image = img;
          asset.needsUpdate = true;
          renderer?.initTexture(asset);
          break;
        case AssetsType.GLTF:
          asset = await AssetsProvider.loadGltf(ad.path);
          break;
        case AssetsType.AUDIO:
          asset = await AssetsProvider.loadAudio(ad.path);
          break;
      }

      AssetsProvider.assets[ad.id] = {
        id: ad.id,
        path: ad.path,
        type: ad.type,
        asset: asset,
      };
      loadedObjects++;

      AssetsProvider.loadingProgress = loadedObjects / assetsData.length;
      callBackProgress(AssetsProvider.loadingProgress);
    }

    return new Promise((resolve) => {
      resolve(AssetsProvider.loadingProgress);
    });
  }

  static getAsset(id: string): any {
    return AssetsProvider.assets[id];
  }

  private static loadImage(path: string): Promise<HTMLImageElement> {
    return new Promise((resolve) => {
      const img = new Image();
      img.onload = (e) => {
        resolve(img);
      };
      img.src = path;
    });
  }

  private static loadVideo(path: string): Promise<HTMLVideoElement> {
    return new Promise((resolve) => {
      const video = new HTMLVideoElement();
      video.onload = (e) => {
        resolve(video);
      };
      video.src = path;
    });
  }

  private static loadGltf(path: string): Promise<GLTF> {
    return new Promise((resolve) => {
      AssetsProvider.gltfLoader.load(path, (gltf: GLTF) => {
        resolve(gltf);
      });
    });
  }

  private static loadAudio(path: string): Promise<HTMLAudioElement> {
    return new Promise((resolve) => {
      const audio = new Audio();
      audio.addEventListener(
        "canplaythrough",
        () => {
          resolve(audio);
        },
        false,
      );
      audio.src = path;
      audio.load();
    });
  }
}

export default AssetsProvider;
