import type { Vec3 } from "../math/Vec3"
import { Collider, type Collider as ColliderShape } from "./Collider"
import type { Terrain } from "./Terrain"

export type CollisionWorld = {
  terrain: Terrain
  staticColliders: ColliderShape[]
  dynamicColliders: ColliderShape[]
}

export namespace CollisionWorld {
  export function create(
    terrain: Terrain,
    staticColliders: ColliderShape[],
  ): CollisionWorld {
    return { terrain, staticColliders, dynamicColliders: [] }
  }

  export function pushOut(
    world: CollisionWorld,
    position: Vec3,
    radius: number,
  ): void {
    pushFrom(world.staticColliders, position, radius)
    pushFrom(world.dynamicColliders, position, radius)
  }

  export function groundHeight(world: CollisionWorld, position: Vec3): number {
    let ground = world.terrain.heightAt(position.x, position.z)
    ground = standingHeight(world.staticColliders, position, ground)
    return standingHeight(world.dynamicColliders, position, ground)
  }

  function pushFrom(
    colliders: ColliderShape[],
    position: Vec3,
    radius: number,
  ): void {
    for (const collider of colliders) {
      if (position.y < collider.top - 0.01) {
        Collider.pushOut(collider, position, radius)
      }
    }
  }

  function standingHeight(
    colliders: ColliderShape[],
    position: Vec3,
    initial: number,
  ): number {
    let ground = initial
    for (const collider of colliders) {
      if (
        collider.standable &&
        Collider.contains(collider, position.x, position.z)
      ) {
        ground = Math.max(ground, collider.top)
      }
    }
    return ground
  }
}
