// from https://medium.com/nicasource/building-an-interactive-web-portfolio-with-vue-three-js-part-three-implementing-three-js-452cb375ef80

import axios from "axios";
import { SpotLight } from "three";
import * as TWEEN from "@tweenjs/tween.js";

import { createCamera } from "./components/camera.js";
import { createLights } from "./components/lights.js";
import { createScene } from "./components/scene.js";
import { createCube, createTerrain } from "./components/objects/terrain.js";
import { Loop } from "./systems/Loop.js";
import { Resizer } from "./systems/Resizer.js";
import { createControls } from "./systems/controls.js";
import { createRenderer } from "./systems/renderer.js";
import { AppString } from "@/constants/app";

// These variables are module-scoped: we cannot access them
// from outside the module

const color = "#42b883";
const color2 = "#0055aa";
const PLATFORM_SIZE = 100;
const PLATFORM_BORDER = 10;
const PLATFORM_EDGE_FOR_UNKNOWNS = 10;
const BASE32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";

function createLight() {
  const light = new SpotLight(0xffffff, 100, 0, Math.PI / 8, 0.5, 0);
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  light.tick = () => {};
  return light;
}

class World {
  constructor(container) {
    this.update = this.update.bind(this);

    // Instances of camera, scene, and renderer
    this.camera = createCamera();
    this.scene = createScene(color2);
    this.renderer = createRenderer();

    this.light = null;
    this.lights = [];

    // Initializae Loop
    this.loop = new Loop(this.camera, this.scene, this.renderer);

    container.append(this.renderer.domElement);

    // Orbit Controls
    const controls = createControls(this.camera, this.renderer.domElement);

    // Light Instance, with optional light helper
    const { light } = createLights(color);

    // Terrain Instance
    const terrain = createTerrain({
      color: color,
      height: PLATFORM_SIZE + PLATFORM_BORDER,
      width: PLATFORM_SIZE + PLATFORM_BORDER + PLATFORM_EDGE_FOR_UNKNOWNS,
    });

    this.loop.updatables.push(controls);
    this.loop.updatables.push(light);
    this.loop.updatables.push(terrain);

    this.scene.add(light, terrain);

    const cube = createCube(-10, 5, 0, 1, 1, 1);
    this.loop.updatables.push(cube);
    this.scene.add(cube);

    new TWEEN.Tween(cube.position).to({ x: 10 }, 5000).start();
    this.loadClaims();

    requestAnimationFrame(this.update);

    // Responsive handler
    const resizer = new Resizer(container, this.camera, this.renderer);
    resizer.onResize = () => {
      this.render();
    };
  }

  update(time) {
    TWEEN.update(time);
    this.lights.forEach((light) => {
      light.updateMatrixWorld();
      light.target.updateMatrixWorld();
    });
    requestAnimationFrame(this.update);
  }

  async loadClaims() {
    const endorserApiServer = AppString.DEFAULT_ENDORSER_API_SERVER;
    try {
      const url = endorserApiServer + "/api/v2/report/claims";
      const headers = { "Content-Type": "application/json" };
      const resp = await axios.get(url, { headers: headers });
      if (resp.status === 200) {
        resp.data.data.map((claim) => {
          const randomness = claim.id.substring(10);
          const x =
            (100 * BASE32.indexOf(randomness.substring(0, 1))) / 32 - 50;
          const z =
            (100 * BASE32.indexOf(randomness.substring(8, 9))) / 32 - 50;
          console.log(
            "randomness",
            randomness,
            randomness.substring(0, 1),
            BASE32.indexOf(randomness.substring(0, 1)),
            x,
            randomness.substring(8, 9),
            BASE32.indexOf(randomness.substring(8, 9)),
            z
          );

          const light = createLight();
          light.position.set(x, 20, z);
          light.target.position.set(x, 0, z);
          this.loop.updatables.push(light);
          this.scene.add(light);
          this.scene.add(light.target);
          new TWEEN.Tween(light.position)
            .to({ y: 5 }, 1000)
            .start()
            .onComplete(() => {
              this.scene.remove(light);
              light.dispose();
            });
          this.lights = [...this.lights, light];
        });
        console.log("done adding cube");
      } else {
        console.log(
          "Got bad response status & data of",
          resp.status,
          resp.data
        );
        // this.alertTitle = "Error With Server";
        // this.alertMessage =
        //   "Got an error retrieving your given time from the server.";
        // this.isAlertVisible = true;
      }
    } catch (error) {
      console.log("Got error of", error);
      // this.alertTitle = "Error With Server";
      // this.alertMessage =
      //   "Got an error retrieving your given time from the server.";
      // this.isAlertVisible = true;
    }
  }

  render() {
    // draw a single frame
    this.renderer.render(this.scene, this.camera);
  }

  // Animation handlers
  start() {
    this.loop.start();
  }

  stop() {
    this.loop.stop();
  }
}

export { World };