import * as THREE from "three";
import type {
  CelestialVisual,
  ClaimVisual,
  ConstructionSiteVisual,
  NodeVisual,
  PlanetVisual,
  Selectable,
  ShipVisual,
  StructureVisual,
} from "./viewerTypes";

/**
 * System rendering layer.
 * Scene coordinate unit: km * DISPLAY_UNITS_PER_KILOMETER * ACTIVE_SYSTEM_DETAIL_SCALE.
 * Camera far plane covers a solar system.
 * Only the active system's objects are visible; inactive system objects are hidden in place.
 */
export class SystemLayer {
  readonly scene = new THREE.Scene();
  readonly camera = new THREE.PerspectiveCamera(50, 1, 0.000005, 300000);

  readonly celestialGroup = new THREE.Group();
  readonly nodeGroup = new THREE.Group();
  readonly stationGroup = new THREE.Group();
  readonly claimGroup = new THREE.Group();
  readonly constructionSiteGroup = new THREE.Group();
  readonly shipGroup = new THREE.Group();

  readonly selectableTargets = new Map<THREE.Object3D, Selectable>();

  readonly planetVisuals: PlanetVisual[] = [];
  readonly shipVisuals = new Map<string, ShipVisual>();
  readonly celestialVisuals = new Map<string, CelestialVisual>();
  readonly nodeVisuals = new Map<string, NodeVisual>();
  readonly stationVisuals = new Map<string, StructureVisual>();
  readonly claimVisuals = new Map<string, ClaimVisual>();
  readonly constructionSiteVisuals = new Map<string, ConstructionSiteVisual>();

  constructor() {
    this.scene.add(new THREE.AmbientLight(0x90a6c0, 0.55));
    const keyLight = new THREE.DirectionalLight(0xdcecff, 1.3);
    keyLight.position.set(1000, 1200, 800);
    this.scene.add(keyLight);
    this.scene.add(
      this.celestialGroup,
      this.nodeGroup,
      this.stationGroup,
      this.claimGroup,
      this.constructionSiteGroup,
      this.shipGroup,
    );
  }

  updateCamera(systemFocus: THREE.Vector3, orbitOffset: THREE.Vector3) {
    this.camera.position.copy(systemFocus).add(orbitOffset);
    this.camera.lookAt(systemFocus);
  }

  onResize(aspect: number) {
    this.camera.aspect = aspect;
    this.camera.updateProjectionMatrix();
  }

  render(renderer: THREE.WebGLRenderer) {
    renderer.render(this.scene, this.camera);
  }
}
