import * as React from "react";
import {
  DirectionalLight,
  Object3D,
  PerspectiveCamera,
  Scene,
  WebGLRenderer,
  AmbientLight,
  Vector3,
  Group,
  Quaternion,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import CSS from "csstype";
import {
  HttpMethod,
  HttpRepository,
  HttpRoute,
} from "../../core/repository/http_repository";
import { useParams } from "react-router-dom";
 

const canvasStyle: CSS.Properties = {
  backgroundColor: "rgb(151 41 41 / 85%)",
};

export const AssemblyPreviewInsertVectorPath = "/insertion_vector/";

export interface AssemblyPreviewInsertionPathModel {
  offset: number;
  count: number;
  parent: string;
  child: string;
  insertions: Insertions;
}

export interface Insertions {
  time: number;
  insertion_path: InsertionPath[];
  status: string;
}

export interface InsertionPath {
  quadrelion: number[];
  xyz: number[];
  euler: number[];
}

export function AssemblyPreviewInsertVector() {
  const container = new Object3D();
  const canvasRef = React.useRef<HTMLCanvasElement>(null);
  const scene = new Scene();
  const camera = new PerspectiveCamera(
    80,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  let renderId = 1;
  let assemblyCounter: undefined | Number = undefined;
  let params = useParams().id;
 
  React.useEffect(() => {
    const renderer = new WebGLRenderer({
      canvas: canvasRef.current as HTMLCanvasElement,
      antialias: true,
      alpha: true,
    });

    camera.position.set(2, 1, 2);

    const directionalLight = new DirectionalLight(0xffffff, 0.2);
    directionalLight.castShadow = true;
    directionalLight.position.set(-1, 2, 4);
    scene.add(directionalLight);

    const ambientLight = new AmbientLight(0xffffff, 0.7);
    scene.add(ambientLight);
    container.position.set(0, 0, 0);

    renderer.setSize(window.innerWidth, window.innerHeight);

    const onResize = () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer!.setSize(window.innerWidth, window.innerHeight);
    };

    window.addEventListener("resize", onResize, false);
    new OrbitControls(camera, renderer.domElement);

    renderer!.setAnimationLoop(() => {
      renderer!.render(scene, camera);
    });
 

    renderObject(1, params!);
  });

  async function renderObject(renderId: Number, projectId: String) {
    const assemblyResponse =
      await HttpRepository.jsonRequest<AssemblyPreviewInsertionPathModel>(
        HttpMethod.GET,
        `${HttpRoute.insertionPath}${projectId}?count=${renderId}`
      );
    const objectControl = (
      await loadObject([assemblyResponse.child, assemblyResponse.parent])
    )[1];

 
    function assemblyAnimate(objectId: Number, coords: InsertionPath, b:boolean) {
      const object = scene.getObjectById(objectId as number);
      const r = 1
      object?.position.set(coords.xyz[0] * r, coords.xyz[1] * r, coords.xyz[2] * r);
      object?.setRotationFromQuaternion(
        new Quaternion(
          coords.quadrelion[0],
          coords.quadrelion[1],
          coords.quadrelion[2],
          coords.quadrelion[3]
        )
      );
      console.log(object?.position)
    }
    function timer(ms: number) {
      return new Promise((res) => setTimeout(res, ms));
    }
    const b = true
    async function load(id: Number, len: number) {
      for (var i = 0; i < len; i++) {

        assemblyAnimate(objectControl, assemblyResponse.insertions.insertion_path[i], b);
        await timer(3);
      }
    }

    assemblyResponse.insertions.insertion_path = assemblyResponse.insertions.insertion_path.reverse()
    load(objectControl, assemblyResponse.insertions.insertion_path.length);
  }

  async function click() {
    renderId = renderId + 1;

    if (assemblyCounter === renderId) {
      renderId = 1;
    }
    scene.clear();
    renderObject(renderId, params!);
  }

  async function loadObject(objectList: string[]): Promise<Number[]> {
    const promises: Array<Promise<Group>> = [];
    objectList.forEach((e) => {
      const fbxLoader = new OBJLoader();
      promises.push(fbxLoader.loadAsync(e));
    });

    const objects = await Promise.all(promises);
    const result: Array<Number> = [];
    for (let i = 0; objects.length > i; i++) {
      const el = objects[i];
      container.add(el);
      scene.add(container);
      result.push(el.id);
      const directionalLight = new DirectionalLight(0xffffff, 0.2);
      directionalLight.castShadow = true;
      directionalLight.position.set(container.position.x - 10,container.position.y - 10,container.position.z - 10);
      scene.add(directionalLight);
      container.position.set(0, 0, 0);
      fitCameraToCenteredObject(camera, container);
    }
    return result;
  }
  function fitCameraToCenteredObject(
    camera: PerspectiveCamera,
    object: Object3D
  ) {
    const dist = 20;
    const vector = new Vector3();

    camera.getWorldDirection(vector);

    vector.multiplyScalar(dist);
    vector.add(camera.position);

    object.position.set(vector.x, vector.y, vector.z);
    object.setRotationFromQuaternion(camera.quaternion);
  }
  return (
    <>
      <div className="loader">
        <div onClick={() => click()}>next</div>
        <canvas style={canvasStyle} ref={canvasRef} />
      </div>
    </>
  );
}
