import * as RE from 'rogue-engine';
import * as CANNON from 'cannon-es';
import * as THREE from 'three';
import CannonBody from '../CannonBody.re';

export default class CannonShape extends RE.Component {
  shape: CANNON.Shape;
  body: CANNON.Body | undefined;
  bodyComponent: CannonBody | undefined;

  localPos: THREE.Vector3 = new THREE.Vector3();
  worldPos = new THREE.Vector3();

  localRot = new THREE.Quaternion();
  worldQuaternion = new THREE.Quaternion();

  private matrixA = new THREE.Matrix4();
  private matrixB = new THREE.Matrix4();
  private matrixC = new THREE.Matrix4();

  awake() {
    this.createShape();
  }

  start() {
    if (!this.shape) return;

    this.bodyComponent = this.getBodyComponent(this.object3d);

    if (!this.bodyComponent) return;

    this.body = this.bodyComponent.body;

    const bodyIsShape = this.object3d === this.bodyComponent.object3d;

    this.object3d.getWorldPosition(this.worldPos);
    this.localPos.copy(this.worldPos);
    this.bodyComponent.object3d.updateWorldMatrix(true, true);
    this.bodyComponent.object3d.worldToLocal(this.localPos);

    let position = new CANNON.Vec3(
      this.localPos.x,
      this.localPos.y,
      this.localPos.z,
    );

    this.object3d.updateWorldMatrix(true, true);
    this.object3d.getWorldQuaternion(this.worldQuaternion);

    this.matrixA.makeRotationFromQuaternion(this.worldQuaternion);
    this.object3d.updateWorldMatrix(true, true);
    this.matrixB.copy(this.bodyComponent.object3d.matrixWorld).invert();
    this.matrixC.extractRotation(this.matrixB);
    this.matrixA.premultiply(this.matrixC);
    this.localRot.setFromRotationMatrix(this.matrixA);

    let rotation = new CANNON.Quaternion(
      this.localRot.x,
      this.localRot.y,
      this.localRot.z,
      this.localRot.w,
    );

    if (bodyIsShape) {
      this.body.addShape(this.shape);
    } else {
      this.body.addShape(this.shape, position, rotation);
    }
  }

  private getBodyComponent(object3d: THREE.Object3D): CannonBody | undefined {
    const bodyComponent = RE.getComponent(CannonBody, object3d);

    if (bodyComponent) {
      return bodyComponent;
    }

    if (!object3d.parent) return;

    return this.getBodyComponent(object3d.parent as THREE.Object3D);
  }

  protected createShape(): void {};
}
