import * as THREE from "three";
import { classifyPovLevel } from "./viewerMath";
import type { PovLevel } from "./viewerTypes";
import type { UniverseLayer } from "./viewerUniverseLayer";
import type { GalaxyLayer } from "./viewerGalaxyLayer";
import type { SystemLayer } from "./viewerSystemLayer";
import type { LocalLayer } from "./viewerLocalLayer";

export interface RenderFrameParams {
  clock: THREE.Clock;
  renderer: THREE.WebGLRenderer;
  universeLayer: UniverseLayer;
  galaxyLayer: GalaxyLayer;
  systemLayer: SystemLayer;
  localLayer: LocalLayer;
  getPovLevel: () => PovLevel;
  updateCamera: (delta: number) => void;
  updateAmbience: (delta: number) => void;
  updatePlanetPresentation: () => void;
  updateShipPresentation: () => void;
  updateNetworkPanel: () => void;
  applyZoomPresentation: () => void;
  recordPerformanceStats: (frameMs: number) => void;
  updatePerformancePanel: () => void;
}

export interface ResizeParams {
  galaxyLayer: GalaxyLayer;
  systemLayer: SystemLayer;
  localLayer: LocalLayer;
  width: number;
  height: number;
}

export interface CameraStepParams {
  currentDistance: number;
  desiredDistance: number;
  orbitPitch: number;
  delta: number;
}

export function renderFrame(params: RenderFrameParams) {
  const frameStartedAtMs = performance.now();
  const delta = Math.min(params.clock.getDelta(), 0.033);
  params.updateCamera(delta);
  params.updateAmbience(delta);
  params.updatePlanetPresentation();
  params.updateShipPresentation();
  params.updateNetworkPanel();
  params.applyZoomPresentation();

  const povLevel = params.getPovLevel();
  const activeCamera = povLevel === "galaxy" ? params.galaxyLayer.camera : params.systemLayer.camera;
  params.renderer.autoClear = false;
  params.renderer.clear();
  // Universe backdrop — always first, rendered with the active camera so it aligns with the foreground
  params.universeLayer.render(params.renderer, activeCamera);
  params.renderer.clearDepth();
  if (povLevel === "galaxy") {
    // Galaxy map on top of universe backdrop
    params.galaxyLayer.render(params.renderer);
  } else if (povLevel === "system") {
    params.systemLayer.render(params.renderer);
  } else {
    // local: system as mid-ground backdrop, then local on top
    params.systemLayer.render(params.renderer);
    params.renderer.clearDepth();
    params.localLayer.render(params.renderer);
  }

  params.recordPerformanceStats(performance.now() - frameStartedAtMs);
  params.updatePerformancePanel();
}

export function resizeViewer(params: ResizeParams) {
  const aspect = params.width / params.height;
  params.galaxyLayer.onResize(aspect);
  params.systemLayer.onResize(aspect);
  params.localLayer.onResize(aspect);
}

export function stepCamera(params: CameraStepParams) {
  const currentDistance = THREE.MathUtils.damp(params.currentDistance, params.desiredDistance, 7.5, params.delta);
  const povLevel = classifyPovLevel(currentDistance);
  const orbitPitch = THREE.MathUtils.clamp(params.orbitPitch, 0.18, 1.3);
  return { currentDistance, povLevel, orbitPitch };
}
