import { track } from "@vercel/analytics";
import { Color, Object3D, type WebGLRenderer } from "three";

import Object3DStep from "@/assets/three/objects/Object3DStep";
import { QUIZ_STEPS } from "@/config/data";
import { type SunoSong } from "@/types";

import CarouselCDs from "./CarouselCDs";

const refsComponents = {
  Object3DStep: Object3DStep,
  CarouselCDs: CarouselCDs,
};

export default class StepsController extends Object3D {
  private Object3DSteps: Array<Object3DStep | CarouselCDs | undefined> = [];

  constructor(
    step: number,
    songs: Array<SunoSong>,
    isMuted: boolean,
    renderer: WebGLRenderer,
  ) {
    super();

    for (let i = 0; i < QUIZ_STEPS.length; i++) {
      const section = QUIZ_STEPS[i];

      // - RGB To Liner background colors
      section.backgroundColors[0] = `#${new Color(section.backgroundColors[0]).convertLinearToSRGB().getHexString()}`;
      section.backgroundColors[1] = `#${new Color(section.backgroundColors[1]).convertLinearToSRGB().getHexString()}`;

      if (section?.model3D) {
        const component = section?.model3D.type as keyof typeof refsComponents;

        const object3DStep = new refsComponents[component](
          section.model3D,
          i === step ? true : false,
          section?.model3D.type === "CarouselCDs",
          isMuted,
          renderer?.capabilities?.isWebGL2,
        );

        if (section?.model3D.type === "CarouselCDs") {
          object3DStep.setResultCovers(songs);
        }

        this.Object3DSteps.push(object3DStep);
        this.add(object3DStep);
      } else {
        this.Object3DSteps.push(undefined);
      }
    }
  }

  setStep(step: number, lastStep: number) {
    const prevObject3DStep = this.Object3DSteps[lastStep];
    if (step !== lastStep) {
      prevObject3DStep?.fadeOut();
      track("page_view:navigation", {
        section: QUIZ_STEPS[step].id,
        step: step,
      });
    }

    const currentObject3DStep = this.Object3DSteps[step];
    currentObject3DStep?.fadeIn(0.85);
  }

  forceTransition(elementIn: number, elementOut: number) {
    const prevObject3DStep = this.Object3DSteps[elementOut];
    prevObject3DStep?.fadeOut();

    const currentObject3DStep = this.Object3DSteps[elementIn];
    currentObject3DStep?.fadeIn(0.85);
  }

  setSongs(songs: Array<SunoSong>) {
    this.Object3DSteps.forEach((obj) => {
      obj?.setResultCovers(songs);
    });
  }

  showError() {
    //TODO: only in the current step
    this.Object3DSteps.forEach((obj) => {
      obj?.showError();
    });
  }

  setSong(song: SunoSong, direction: number) {
    this.Object3DSteps.forEach((obj) => {
      obj?.setSong(song, direction);
    });
  }

  onScrollResults(scroll: number) {
    this.Object3DSteps.forEach((obj) => {
      obj?.onScrollResults(scroll);
    });
  }

  setIsMuted(isMuted: boolean) {
    this.Object3DSteps.forEach((obj) => {
      obj?.setIsMuted(isMuted);
    });
  }

  update(delta: number) {
    this.Object3DSteps.forEach((obj) => {
      obj?.update(delta);
    });
  }
}
