import { Shape } from '../shapes/Shape'
import { Vec3 } from '../math/Vec3'
import type { Quaternion } from '../math/Quaternion'

/**
 * A plane, facing in the Z direction. The plane has its surface at z=0 and everything below z=0 is assumed to be solid plane. To make the plane face in some other direction than z, you must put it inside a Body and rotate that body. See the demos.
 * @example
 *     const planeShape = new CANNON.Plane()
 *     const planeBody = new CANNON.Body({ mass: 0, shape:  planeShape })
 *     planeBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0) // make it face up
 *     world.addBody(planeBody)
 */
export class Plane extends Shape {
  /** worldNormal */
  worldNormal: Vec3
  /** worldNormalNeedsUpdate */
  worldNormalNeedsUpdate: boolean
  boundingSphereRadius: number

  constructor() {
    super({ type: Shape.types.PLANE })

    // World oriented normal
    this.worldNormal = new Vec3()
    this.worldNormalNeedsUpdate = true

    this.boundingSphereRadius = Number.MAX_VALUE
  }

  /** computeWorldNormal */
  computeWorldNormal(quat: Quaternion): void {
    const n = this.worldNormal
    n.set(0, 0, 1)
    quat.vmult(n, n)
    this.worldNormalNeedsUpdate = false
  }

  calculateLocalInertia(mass: number, target = new Vec3()): Vec3 {
    return target
  }

  volume(): number {
    return (
      // The plane is infinite...
      Number.MAX_VALUE
    )
  }

  calculateWorldAABB(pos: Vec3, quat: Quaternion, min: Vec3, max: Vec3): void {
    // The plane AABB is infinite, except if the normal is pointing along any axis
    tempNormal.set(0, 0, 1) // Default plane normal is z
    quat.vmult(tempNormal, tempNormal)
    const maxVal = Number.MAX_VALUE
    min.set(-maxVal, -maxVal, -maxVal)
    max.set(maxVal, maxVal, maxVal)

    if (tempNormal.x === 1) {
      max.x = pos.x
    } else if (tempNormal.x === -1) {
      min.x = pos.x
    }

    if (tempNormal.y === 1) {
      max.y = pos.y
    } else if (tempNormal.y === -1) {
      min.y = pos.y
    }

    if (tempNormal.z === 1) {
      max.z = pos.z
    } else if (tempNormal.z === -1) {
      min.z = pos.z
    }
  }

  updateBoundingSphereRadius(): void {
    this.boundingSphereRadius = Number.MAX_VALUE
  }
}

const tempNormal = new Vec3()
