import * as THREE from 'three';
import { DIRECTIONS } from '../engine/dungeon/Constants.js';

export class CameraManager {
    constructor(renderer) {
        this.renderer = renderer; // Reference to GameRenderer to access scenes/resize if needed

        // Configuration
        // Configuration
        this.zoomLevel = 2.5; // Orthographic zoom factor (Lower = Closer)
        this.aspect = window.innerWidth / window.innerHeight;

        // Isometric Setup: Orthographic Camera
        this.camera = new THREE.OrthographicCamera(
            -this.zoomLevel * this.aspect,
            this.zoomLevel * this.aspect,
            this.zoomLevel,
            -this.zoomLevel,
            1,
            1000
        );

        // Initial Position: Isometric View
        this.target = new THREE.Vector3(0, 0, 0); // Focus point
        this.isoOffset = new THREE.Vector3(20, 20, 20); // Relative offset

        this.camera.position.copy(this.target).add(this.isoOffset);
        this.camera.lookAt(this.target);

        // --- Controls State ---
        this.isDragging = false;
        this.lastMouseX = 0;
        this.lastMouseY = 0;
        this.panSpeed = 0.5;

        // Current Snap View (North, East, South, West)
        this.currentViewAngle = 0;

        // Animation state for smooth transitions
        this.isAnimating = false;
        this.animationStartPos = new THREE.Vector3();
        this.animationTargetPos = new THREE.Vector3();
        this.animationProgress = 0;
        this.animationDuration = 0.5; // seconds
        this.animationStartTime = 0;

        this.setupInputListeners();
    }

    getCamera() {
        return this.camera;
    }

    centerOn(x, y) {
        // Calculate current offset relative to OLD target
        const currentOffset = this.camera.position.clone().sub(this.target);

        // Update target: Grid (x, y) -> World (x, 0, -y)
        this.target.set(x, 0, -y);

        // Restore position with new target + same relative offset
        this.camera.position.copy(this.target).add(currentOffset);
        this.camera.lookAt(this.target);
    }

    setupInputListeners() {
        // Zoom (Mouse Wheel)
        window.addEventListener('wheel', (e) => {
            e.preventDefault();
            // Adjust Zoom Level property
            if (e.deltaY < 0) this.zoomLevel = Math.max(3, this.zoomLevel - 1);
            else this.zoomLevel = Math.min(30, this.zoomLevel + 1);

            this.updateProjection();
        }, { passive: false });

        // Pan Listeners (Middle Click)
        window.addEventListener('mousedown', (e) => {
            if (e.button === 1) { // Middle Mouse
                this.isDragging = true;
                this.lastMouseX = e.clientX;
                this.lastMouseY = e.clientY;
            }
        });

        window.addEventListener('mouseup', () => {
            this.isDragging = false;
        });

        window.addEventListener('mousemove', (e) => {
            if (this.isDragging) {
                const dx = e.clientX - this.lastMouseX;
                const dy = e.clientY - this.lastMouseY;
                this.lastMouseX = e.clientX;
                this.lastMouseY = e.clientY;

                this.pan(-dx, dy);
            }
        });

        // Resize Listener linkage
        window.addEventListener('resize', () => {
            this.aspect = window.innerWidth / window.innerHeight;
            this.updateProjection();
        });
    }

    updateProjection() {
        this.camera.left = -this.zoomLevel * this.aspect;
        this.camera.right = this.zoomLevel * this.aspect;
        this.camera.top = this.zoomLevel;
        this.camera.bottom = -this.zoomLevel;
        this.camera.updateProjectionMatrix();
    }

    pan(dx, dy) {
        // Move Target and Camera together
        // We pan on the logical "Ground Plane" relative to screen movement

        const moveSpeed = this.panSpeed * 0.05 * (this.zoomLevel / 10);

        // Transform screen delta to world delta
        // In Iso view, Right on screen = (1, 0, 1) in world? 
        // Or using camera right/up vectors

        const right = new THREE.Vector3(1, 0, 1).normalize(); // Approx logic for standard Iso
        const forward = new THREE.Vector3(-1, 0, 1).normalize();

        // Let's use camera vectors for generic support
        // Project camera right/up onto XZ plane
        // Or just direct translation:

        this.camera.translateX(dx * moveSpeed);
        this.camera.translateY(dy * moveSpeed);

        // This moves camera. We need to update target reference too if we want to snap back correctly
        // But for now, simple pan is "offsetting everything".
        // centerOn resets this.
    }

    update(deltaTime) {
        // Update camera animation if active
        if (this.isAnimating) {
            const elapsed = (performance.now() - this.animationStartTime) / 1000;
            this.animationProgress = Math.min(elapsed / this.animationDuration, 1);

            // Easing function (ease-in-out)
            const t = this.animationProgress;
            const eased = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;

            // Interpolate position
            this.camera.position.lerpVectors(this.animationStartPos, this.animationTargetPos, eased);
            this.camera.lookAt(this.target);

            // End animation
            if (this.animationProgress >= 1) {
                this.isAnimating = false;
                this.camera.position.copy(this.animationTargetPos);
            }
        }
    }

    // --- Fixed Orbit Logic ---
    setIsoView(direction) {
        // Rotate camera around target while maintaining isometric angle
        // Isometric view: 45 degree angle from horizontal
        const distance = 28; // Distance from target
        const isoAngle = Math.PI / 4; // 45 degrees for isometric view

        // Horizontal rotation angle based on direction
        let horizontalAngle = 0;
        switch (direction) {
            case DIRECTIONS.NORTH: // 'N'
                horizontalAngle = Math.PI / 4; // 45 degrees (NE in isometric)
                break;
            case DIRECTIONS.EAST: // 'E'
                horizontalAngle = -Math.PI / 4; // -45 degrees (SE in isometric)
                break;
            case DIRECTIONS.SOUTH: // 'S'
                horizontalAngle = -3 * Math.PI / 4; // -135 degrees (SW in isometric)
                break;
            case DIRECTIONS.WEST: // 'W'
                horizontalAngle = 3 * Math.PI / 4; // 135 degrees (NW in isometric)
                break;
        }

        // Calculate camera position maintaining isometric angle
        // x and z form a circle on the horizontal plane
        // y is elevated to maintain the isometric angle
        const horizontalDistance = distance * Math.cos(isoAngle);
        const height = distance * Math.sin(isoAngle);

        const x = this.target.x + horizontalDistance * Math.cos(horizontalAngle);
        const z = this.target.z + horizontalDistance * Math.sin(horizontalAngle);

        // Start animation instead of instant change
        this.animationStartPos.copy(this.camera.position);
        this.animationTargetPos.set(x, height, z);
        this.animationProgress = 0;
        this.animationStartTime = performance.now();
        this.isAnimating = true;

        this.currentViewAngle = horizontalAngle;
    }
}
