import * as THREE from "three";
import type { CameraState } from "../types";

interface AutoCameraOptions {
  aspect?: number;
  fovDegrees?: number;
  padding?: number;
}

export function computeAutoCamera(
  globalBox: THREE.Box3,
  options: AutoCameraOptions = {}
): CameraState {
  const center = new THREE.Vector3();
  globalBox.getCenter(center);

  const aspect = Math.max(options.aspect ?? 1, 0.1);
  const viewDirection = new THREE.Vector3(0.08, 0.05, 1).normalize();
  const worldUp = new THREE.Vector3(0, 1, 0);
  const forward = viewDirection.clone().negate();
  const right = new THREE.Vector3().crossVectors(forward, worldUp).normalize();
  const cameraUp = new THREE.Vector3().crossVectors(right, forward).normalize();
  const halfVerticalFov = THREE.MathUtils.degToRad(options.fovDegrees ?? 60) * 0.5;
  const tanHalfVerticalFov = Math.tan(halfVerticalFov);
  const tanHalfHorizontalFov = tanHalfVerticalFov * aspect;

  const corners = [
    new THREE.Vector3(globalBox.min.x, globalBox.min.y, globalBox.min.z),
    new THREE.Vector3(globalBox.min.x, globalBox.min.y, globalBox.max.z),
    new THREE.Vector3(globalBox.min.x, globalBox.max.y, globalBox.min.z),
    new THREE.Vector3(globalBox.min.x, globalBox.max.y, globalBox.max.z),
    new THREE.Vector3(globalBox.max.x, globalBox.min.y, globalBox.min.z),
    new THREE.Vector3(globalBox.max.x, globalBox.min.y, globalBox.max.z),
    new THREE.Vector3(globalBox.max.x, globalBox.max.y, globalBox.min.z),
    new THREE.Vector3(globalBox.max.x, globalBox.max.y, globalBox.max.z),
  ];

  let distance = 0.01;
  for (const corner of corners) {
    const offset = corner.clone().sub(center);
    const depthOffset = offset.dot(viewDirection);
    const horizontal = Math.abs(offset.dot(right));
    const vertical = Math.abs(offset.dot(cameraUp));

    distance = Math.max(
      distance,
      depthOffset + horizontal / Math.max(tanHalfHorizontalFov, 1e-3),
      depthOffset + vertical / Math.max(tanHalfVerticalFov, 1e-3)
    );
  }

  distance *= options.padding ?? 1.0;
  const position = center.clone().addScaledVector(viewDirection, distance);

  return {
    position: {
      x: position.x,
      y: position.y,
      z: position.z,
    },
    target: { x: center.x, y: center.y, z: center.z },
    zoom: 1,
    up: { x: 0, y: 1, z: 0 },
  };
}

export function mergeBoxes(boxes: THREE.Box3[]): THREE.Box3 {
  const merged = new THREE.Box3();
  for (const b of boxes) {
    merged.union(b);
  }
  return merged;
}
