import {
  DoubleSide,
  Group,
  LinearFilter,
  Material,
  Mesh,
  MeshBasicMaterial,
  PlaneBufferGeometry,
  TextureLoader,
  Vector3,
  sRGBEncoding,
} from "three-platformize";

export class ShadowModel {
  mesh: Mesh;

  private showTime: NodeJS.Timeout;
  private hideTime: NodeJS.Timeout;

  constructor(
    url: string,
    width: number,
    height: number,
    rotation: { x: number; y: number; z: number },
    position: Vector3,
    scale: number,
    model: Group
  ) {
    const texture = new TextureLoader().load(url);
    const planeBufferGeometry = new PlaneBufferGeometry(width, height);

    texture.magFilter = LinearFilter;
    texture.minFilter = LinearFilter;
    texture.encoding = sRGBEncoding;
    texture.repeat.set(1, 1);

    const meshBasicMaterial = new MeshBasicMaterial({
      color: 16777215,
      map: texture,
      transparent: true,
      side: DoubleSide,
      opacity: 1,
    });

    this.mesh = new Mesh(planeBufferGeometry, meshBasicMaterial);
    this.mesh.rotation.set(rotation.x, rotation.y, rotation.z);
    this.mesh.position.copy(position);
    this.mesh.scale.set(scale, scale, scale);

    model.add(this.mesh);
    this.show();
  }

  show(cb?: Function) {
    this.mesh.visible = true;
    // @ts-ignore
    this.mesh.material.map.offset.y += 0.01;

    this.clearTimer();

    this.showTime = setInterval(() => {
      const material = this.mesh.material as Material;
      material.opacity += 0.02;

      if (material.opacity >= 1) {
        material.opacity = 1;
        clearInterval(this.showTime);

        cb && cb();
      }
    }, 20);
  }

  hide(cb?: Function) {
    this.clearTimer();

    this.hideTime = setInterval(() => {
      const material = this.mesh.material as Material;
      material.opacity -= 0.05;

      if (material.opacity <= 0) {
        clearInterval(this.hideTime);
        material.opacity = 0;
        this.mesh.visible = false;

        cb && cb();
      }
    });
  }

  clearTimer() {
    if (this.hideTime) {
      clearInterval(this.hideTime);
    }

    if (this.showTime) {
      clearInterval(this.showTime);
    }
  }
}
