import { Object3D } from "three";

import { wrap } from "@/helpers/math";
import type { QuizSectionItemModel3D, SunoSong } from "@/types";

import { type InterfaceObject3DStep } from "./InterfaceObject3DStep";
import Object3DStep from "./Object3DStep";
export default class CarouselCDs
  extends Object3D
  implements InterfaceObject3DStep
{
  private modelData: QuizSectionItemModel3D;
  private POSITION_Y = 0.175;
  private INITIAL_POSITION_Z = -1.5;
  private POSITION_Z = this.INITIAL_POSITION_Z;
  private ROTATION_X = 0.3;
  private RADIUS = 1.5;
  private ITEMS_CAROUSEL = 3;
  private angle = (Math.PI * 2) / this.ITEMS_CAROUSEL;
  private initialAngle = Math.PI / 2;
  private targetAngle = 0;
  private currentCD = 0;
  private isMuted: boolean;
  private songs: Array<SunoSong> = [];
  private isAlreadyFadeIn: boolean = false;
  meshes: Array<Object3DStep> = [];

  constructor(
    modelData: QuizSectionItemModel3D,
    fadeInOnLoad: boolean = false,
    needsClone: boolean = false,
    isMuted: boolean,
    isWebGL2: boolean,
  ) {
    super();
    this.modelData = modelData;
    this.isMuted = isMuted;
    this.position.set(0, this.POSITION_Y, 0);
    this.rotation.x = this.ROTATION_X;

    for (let i = 0; i < this.ITEMS_CAROUSEL; i++) {
      const object3DStep = new Object3DStep(
        modelData,
        fadeInOnLoad,
        needsClone,
        isWebGL2,
      );

      object3DStep.userData.angle = this.angle * i + this.initialAngle;

      // object3DStep.position.x = Math.PI * 0.5 * i;
      this.meshes.push(object3DStep);
      this.add(object3DStep);
    }

    if (fadeInOnLoad) {
      this.fadeIn(0.5);
      this.meshes.forEach((mesh) => mesh.fadeIn(0.5));
    }
  }
  fadeIn(delay: number = 0) {
    if (this.isAlreadyFadeIn) return;
    this.meshes.forEach((mesh) => mesh.fadeIn(delay));
    this.isAlreadyFadeIn = true;
  }
  fadeOut() {
    this.isAlreadyFadeIn = false;
    this.meshes.forEach((mesh) => mesh.fadeOut());
  }
  showError() {}
  update(delta: number) {
    this.targetAngle += (this.currentCD * this.angle - this.targetAngle) * 0.05;

    this.meshes.forEach((mesh, i) => {
      const angle = mesh.userData.angle + this.targetAngle;
      mesh.position.set(
        Math.cos(angle) * this.RADIUS,
        0,
        this.POSITION_Z + Math.sin(angle) * this.RADIUS,
      );
      mesh.update(delta);
    });
  }
  songsAlreadyStored(songs: Array<SunoSong>) {
    return songs.every((s, index) => s.id === this.songs[index]?.id);
  }
  setResultCovers(songs: Array<SunoSong>) {
    if (!this.songsAlreadyStored(songs)) {
      this.position.y = this.POSITION_Y;
      this.POSITION_Z = this.INITIAL_POSITION_Z;
      this.currentCD = 0;
    }
    this.songs = songs;
    this.meshes.forEach((mesh, index) => {
      if (songs[index]) {
        mesh.visible = true;
        mesh.setResultCover(songs[index]?.image_url);
      } else {
        mesh.visible = false;
      }
    });
    this.setRotateCD();
  }
  setRotateCD() {
    const rotateCDIndex = wrap(
      this.songs.length,
      this.songs.length - this.currentCD,
    );
    this.meshes.forEach((mesh, index) => {
      mesh.rotateCD = index === rotateCDIndex && !this.isMuted;
    });
  }
  setIsMuted(isMuted: boolean) {
    this.isMuted = isMuted;
    this.setRotateCD();
  }
  setSong(song: SunoSong, direction: number = 1) {
    if (!this.songs.length) return;
    const currentIndex = this.songs.findIndex((s) => s.id === song.id);
    const rotateCDIndex = wrap(
      this.songs.length,
      this.songs.length - this.currentCD,
    );
    if (currentIndex === rotateCDIndex) return;
    this.currentCD -= direction;
    this.setRotateCD();
  }

  onScrollResults(scroll: number) {
    this.POSITION_Z = this.INITIAL_POSITION_Z - 0.5 * scroll;
    this.position.y = this.POSITION_Y - 0.15 * scroll;
  }
  setResultCover() {}
}
