/**
 * Railtrack Pro - Three.js Renderer
 * Handles 3D scene setup, camera, and rendering loop
 * @author Railtrack Pro Development Team
 */

class Renderer {
    constructor() {
        this.scene = null;
        this.camera = null;
        this.renderer = null;
        this.controls = null;
        this.gridHelper = null;
        this.trackMeshes = [];
        this.selectedObject = null;
        this.isDragging = false;
        this.raycaster = new THREE.Raycaster();
        this.mouse = new THREE.Vector2();
        
        this.init();
    }

    /**
     * Initialize Three.js scene with camera, renderer, and controls
     */
    init() {
        // Create scene
        this.scene = new THREE.Scene();
        this.scene.background = new THREE.Color(0x1a1a2e);
        this.scene.fog = new THREE.Fog(0x1a1a2e, 50, 200);

        // Create camera
        this.camera = new THREE.PerspectiveCamera(
            60,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );
        this.camera.position.set(20, 20, 20);
        this.camera.lookAt(0, 0, 0);

        // Create renderer
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setSize(window.innerWidth - 50, window.innerHeight - 150);
        this.renderer.shadowMap.enabled = true;
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        document.getElementById('viewport').appendChild(this.renderer.domElement);

        // Add orbit controls
        this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
        this.controls.enableDamping = true;
        this.controls.dampingFactor = 0.05;
        this.controls.maxPolarAngle = Math.PI / 2 - 0.1;
        this.controls.minDistance = 5;
        this.controls.maxDistance = 100;

        // Add lighting
        this.setupLighting();

        // Add ground grid
        this.addGridHelper();

        // Add event listeners
        this.addEventListeners();

        // Start animation loop
        this.animate();

        console.log('[Renderer] Initialized successfully');
    }

    /**
     * Setup scene lighting
     */
    setupLighting() {
        // Ambient light
        const ambientLight = new THREE.AmbientLight(0x404040, 1);
        this.scene.add(ambientLight);

        // Directional light (sun)
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(20, 30, 20);
        directionalLight.castShadow = true;
        directionalLight.shadow.mapSize.width = 2048;
        directionalLight.shadow.mapSize.height = 2048;
        directionalLight.shadow.camera.near = 0.5;
        directionalLight.shadow.camera.far = 100;
        directionalLight.shadow.camera.left = -50;
        directionalLight.shadow.camera.right = 50;
        directionalLight.shadow.camera.top = 50;
        directionalLight.shadow.camera.bottom = -50;
        this.scene.add(directionalLight);

        // Point light near center
        const pointLight = new THREE.PointLight(0xfb5607, 0.5, 30);
        pointLight.position.set(0, 10, 0);
        this.scene.add(pointLight);

        console.log('[Renderer] Lighting setup complete');
    }

    /**
     * Add ground plane with grid helper
     */
    addGridHelper() {
        // Ground plane
        const planeGeometry = new THREE.PlaneGeometry(100, 100);
        const planeMaterial = new THREE.MeshStandardMaterial({
            color: 0x2a2a4e,
            roughness: 0.8,
            metalness: 0.2
        });
        const ground = new THREE.Mesh(planeGeometry, planeMaterial);
        ground.rotation.x = -Math.PI / 2;
        ground.receiveShadow = true;
        this.scene.add(ground);

        // Grid helper
        this.gridHelper = new THREE.GridHelper(100, 50, 0x404080, 0x202040);
        this.scene.add(this.gridHelper);

        // Axis helper
        const axesHelper = new THREE.AxesHelper(5);
        this.scene.add(axesHelper);

        console.log('[Renderer] Grid helper added');
    }

    /**
     * Add event listeners for mouse interactions
     */
    addEventListeners() {
        window.addEventListener('resize', () => this.onWindowResize());
        this.renderer.domElement.addEventListener('mousedown', (e) => this.onMouseDown(e));
        this.renderer.domElement.addEventListener('mousemove', (e) => this.onMouseMove(e));
        this.renderer.domElement.addEventListener('mouseup', (e) => this.onMouseUp(e));
        this.renderer.domElement.addEventListener('click', (e) => this.onClick(e));
        this.renderer.domElement.addEventListener('contextmenu', (e) => e.preventDefault());
    }

    /**
     * Handle window resize
     */
    onWindowResize() {
        const viewport = document.getElementById('viewport');
        this.camera.aspect = viewport.clientWidth / viewport.clientHeight;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(viewport.clientWidth, viewport.clientHeight);
    }

    /**
     * Handle mouse down event
     */
    onMouseDown(event) {
        this.isDragging = true;
        this.updateMouse(event);
        this.raycaster.setFromCamera(this.mouse, this.camera);
        
        // Track track meshes
        const intersects = this.raycaster.intersectObjects(this.trackMeshes);
        if (intersects.length > 0) {
            this.selectedObject = intersects[0].object;
            this.highlightSelection(this.selectedObject);
        } else {
            this.deselectAll();
        }
    }

    /**
     * Handle mouse move event
     */
    onMouseMove(event) {
        this.updateMouse(event);
        
        // Highlight object under cursor
        this.raycaster.setFromCamera(this.mouse, this.camera);
        const intersects = this.raycaster.intersectObjects(this.trackMeshes);
        
        if (intersects.length > 0 && intersects[0].object !== this.selectedObject) {
            this.highlightHover(intersects[0].object);
        } else {
            this.removeHoverHighlight();
        }
    }

    /**
     * Handle mouse up event
     */
    onMouseUp() {
        this.isDragging = false;
    }

    /**
     * Handle click event
     */
    onClick(event) {
        if (!this.isDragging && this.selectedObject) {
            console.log('[Renderer] Track clicked:', this.selectedObject.userData);
            Game.onTrackClick(this.selectedObject);
        }
    }

    /**
     * Update mouse position from event
     */
    updateMouse(event) {
        const rect = this.renderer.domElement.getBoundingClientRect();
        this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
    }

    /**
     * Highlight selected object
     */
    highlightSelection(object) {
        // Remove previous highlight
        if (object.originalColor) {
            object.material.emissive.setHex(object.originalColor);
        }
        
        // Store original color and set highlight
        object.originalColor = object.material.emissive.getHex();
        object.material.emissive.setHex(0xfb5607);
        this.selectedObject = object;
        
        // Update info panel
        Game.updateSelectedInfo(object);
    }

    /**
     * Highlight hover object
     */
    highlightHover(object) {
        if (object.hoverColor) {
            object.material.emissive.setHex(object.hoverColor);
        } else {
            object.hoverColor = object.material.emissive.getHex();
            object.material.emissive.setHex(0x404080);
        }
    }

    /**
     * Remove hover highlight
     */
    removeHoverHighlight() {
        for (const mesh of this.trackMeshes) {
            if (mesh.hoverColor) {
                mesh.material.emissive.setHex(mesh.hoverColor);
                delete mesh.hoverColor;
            }
        }
    }

    /**
     * Deselect all objects
     */
    deselectAll() {
        if (this.selectedObject) {
            if (this.selectedObject.originalColor) {
                this.selectedObject.material.emissive.setHex(this.selectedObject.originalColor);
            }
            this.selectedObject = null;
        }
        Game.updateSelectedInfo(null);
    }

    /**
     * Add track piece to scene
     */
    addTrackPiece(geometry, material, position, rotation) {
        const mesh = new THREE.Mesh(geometry, material);
        mesh.position.copy(position);
        mesh.rotation.set(rotation.x, rotation.y, rotation.z);
        mesh.castShadow = true;
        mesh.receiveShadow = true;
        mesh.userData = { type: 'track', id: this.trackMeshes.length };
        
        this.scene.add(mesh);
        this.trackMeshes.push(mesh);
        return mesh;
    }

    /**
     * Remove track piece from scene
     */
    removeTrackPiece(mesh) {
        const index = this.trackMeshes.indexOf(mesh);
        if (index > -1) {
            this.trackMeshes.splice(index, 1);
            this.scene.remove(mesh);
            mesh.geometry.dispose();
            mesh.material.dispose();
        }
    }

    /**
     * Animation loop
     */
    animate() {
        requestAnimationFrame(() => this.animate());
        this.controls.update();
        this.renderer.render(this.scene, this.camera);
    }
}

// Export for module usage
if (typeof module !== 'undefined' && module.exports) {
    module.exports = Renderer;
}
