import {ElementRef, Injectable} from '@angular/core';
import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
import {ThemeService} from '@shared-components/theme/theme.service';
import {THEME_MODE} from '@custom-types/constant';

/**
 * Service responsible for managing the Three.js rendering environment
 */
@Injectable({
  providedIn: 'root'
})
export class RendererService {
  scene!: THREE.Scene;
  camera!: THREE.PerspectiveCamera;
  renderer!: THREE.WebGLRenderer;
  controls!: OrbitControls;
  private currentTheme: THEME_MODE = THEME_MODE.LIGHT;

  constructor(private themeService: ThemeService) {
    this.themeService.theme$.subscribe(theme => {
      this.currentTheme = theme;
      if (this.scene) {
        this.setBackgroundColor();
      }
    })
  }

  /**
   * Initializes the Three.js scene, camera, renderer, and controls
   */
  initializeRenderer(container: ElementRef): void {
    // Create scene
    this.scene = new THREE.Scene();
    this.setBackgroundColor();

    // Get container dimensions
    const containerWidth = container.nativeElement.clientWidth;
    const containerHeight = container.nativeElement.clientHeight;

    // Create camera
    this.camera = new THREE.PerspectiveCamera(75, containerWidth / containerHeight, 0.1, 1000);
    this.camera.position.set(-1, 2, 3);
    this.camera.lookAt(0, 1, 0);

    // Create renderer
    this.renderer = new THREE.WebGLRenderer({antialias: true});
    this.renderer.setSize(containerWidth, containerHeight);

    // Center the canvas in the container
    this.renderer.domElement.style.display = 'block';
    this.renderer.domElement.style.margin = 'auto';

    container.nativeElement.appendChild(this.renderer.domElement);

    // Initialize orbit controls
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.controls.enableDamping = true;
    this.controls.dampingFactor = 0.05;
    this.controls.minDistance = 0.5;
    this.controls.maxDistance = 4;
    this.controls.target.set(0, 1, 0);
    this.controls.update();

    // Add lights
    this.addLights();
  }

  private setBackgroundColor() {
    this.scene.background = new THREE.Color(this.currentTheme === THEME_MODE.DARK ? 0x242526 : 0xFBFBFE);
  }

  /**
   * Resets the camera to its default position and orientation.
   */
  public resetCamera(): void {
    this.camera.position.set(-1, 2, 3);
    this.camera.lookAt(0, 1, 0);
    this.controls.target.set(0, 1, 0);
    this.controls.update();
  }

  /**
   * Adds lighting to the scene
   */
  private addLights(): void {
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    this.scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(1, 1, 1);
    this.scene.add(directionalLight);
  }

  /**
   * Handles window resize events
   */
  onWindowResize(container: ElementRef): void {
    const containerWidth = container.nativeElement.clientWidth;
    const containerHeight = 400; // Fixed height as defined in CSS

    this.camera.aspect = containerWidth / containerHeight;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(containerWidth, containerHeight);
  }

  /**
   * Renders the scene
   */
  render(): void {
    if (this.controls) {
      this.controls.update();
    }

    this.renderer.render(this.scene, this.camera);
  }
}
