import * as THREE from 'three';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
// Note: In some environments this might need to be 'three/addons/controls/PointerLockControls.js'
// but we'll stick to this for now as it's standard examples path.

export class Player {
    constructor(camera, colliders) {
        this.camera = camera;
        this.camera.rotation.order = 'YXZ'; // Standard FPS rotation order to prevent gimbal lock
        this.colliders = colliders;

        // Player stats
        this.speed = 3.0; // Slower "Horror" walk speed
        this.height = 1.7; // Eyes height

        // Init controls
        try {
            this.controls = new PointerLockControls(camera, document.body);
            window.log('PointerLockControls initialized');
        } catch (e) {
            window.log(`ERROR initializing controls: ${e.message}`);
        }

        // Movement state
        this.moveForward = false;
        this.moveBackward = false;
        this.moveLeft = false;
        this.moveRight = false;
        this.adjustDim = false; // 'K' key
        this.adjustBright = false; // 'L' key
        this.velocity = new THREE.Vector3();
        this.direction = new THREE.Vector3();
        this.direction = new THREE.Vector3();
        this.flashlightOn = true; // Started as ON
        this.battery = 100.0;
        this.battery = 100.0;
        this.baseDrain = 0.5; // Drain per second at base intensity

        // Animation
        this.headBobTimer = 0;
        this.lastStepTime = 0;

        // Audio
        this.ctx = new (window.AudioContext || window.webkitAudioContext)();
        this.audioEnabled = false;

        // Animation
        this.headBobTimer = 0;

        this.baseDrain = 0.5; // Drain per second at base intensity

        this.setupInput();
        this.setupFlashlight();
    }

    setupFlashlight() {
        this.flashlight = new THREE.SpotLight(0xffffff, 10);
        this.flashlight.angle = Math.PI / 6;
        this.flashlight.penumbra = 0.3;
        this.flashlight.decay = 1.5; // Lower decay for further reach
        this.flashlight.distance = 60; // Significantly increased range

        this.camera.add(this.flashlight);
        this.flashlight.position.set(0, 0, 0);
        this.flashlight.target.position.set(0, 0, -1);
        this.camera.add(this.flashlight.target);
    }

    setupInput() {
        const onKeyDown = (event) => {
            // Resume Audio Context on first interaction
            if (this.ctx && this.ctx.state === 'suspended') {
                this.ctx.resume();
                this.audioEnabled = true;
            }

            switch (event.code) {
                case 'KeyW': this.moveForward = true; break;
                case 'KeyA': this.moveLeft = true; break;
                case 'KeyS': this.moveBackward = true; break;
                case 'KeyD': this.moveRight = true; break;
                case 'KeyF': this.toggleFlashlight(); break;
                case 'KeyK': this.adjustDim = true; break;
                case 'KeyL': this.adjustBright = true; break;
            }
        };

        const onKeyUp = (event) => {
            switch (event.code) {
                case 'KeyW': this.moveForward = false; break;
                case 'KeyA': this.moveLeft = false; break;
                case 'KeyS': this.moveBackward = false; break;
                case 'KeyD': this.moveRight = false; break;
                case 'KeyK': this.adjustDim = false; break;
                case 'KeyL': this.adjustBright = false; break;
            }
        };

        document.addEventListener('keydown', onKeyDown);
        document.addEventListener('keyup', onKeyUp);
    }

    toggleFlashlight() {
        if (!this.controls) return;
        // Note: isLocked might be false if user escaped, but we allow 'F' if controls exist? 
        // Better to allow F only when locked to avoid confusion.
        if (!this.controls.isLocked) return;

        if (this.battery <= 0 && this.flashlightOn === false) {
            window.log('Cannot turn on: Battery empty');
            return;
        }

        this.flashlightOn = !this.flashlightOn;
        if (this.flashlight) {
            this.flashlight.visible = this.flashlightOn;
        }
    }

    lockControls() {
        if (this.controls) {
            this.controls.lock();
            window.log('Player.lockControls() called');
        } else {
            window.log('WARNING: Controls not initialized for locking');
        }
    }

    getObject() {
        // PointerLockControls in this version operates directly on the camera
        return this.camera;
    }

    update(dt) {
        if (!this.controls) return;

        // Debug logging for lock state (once per second roughly)
        if (Math.random() < 0.01) {
            // window.log(`Controls Locked: ${this.controls.isLocked}`); 
        }

        if (!this.controls.isLocked) return;

        // Friction-like dampening (simple decay)
        this.velocity.x -= this.velocity.x * 10.0 * dt;
        this.velocity.z -= this.velocity.z * 10.0 * dt;

        this.direction.z = Number(this.moveForward) - Number(this.moveBackward);
        this.direction.x = Number(this.moveRight) - Number(this.moveLeft);
        this.direction.normalize();

        const accel = this.speed * 10.0; // Acceleration to reach max speed against friction (assuming friction 10)

        if (this.moveForward || this.moveBackward) this.velocity.z -= this.direction.z * accel * dt;
        if (this.moveLeft || this.moveRight) this.velocity.x -= this.direction.x * accel * dt;

        // Apply movement
        this.controls.moveRight(-this.velocity.x * dt);
        this.controls.moveForward(-this.velocity.z * dt);

        // Simple Collision: Push back
        const playerPos = this.camera.position;
        const playerRadius = 0.5;

        for (const collider of this.colliders) {
            const box = new THREE.Box3().setFromObject(collider);
            if (playerPos.x > box.min.x - playerRadius && playerPos.x < box.max.x + playerRadius &&
                playerPos.z > box.min.z - playerRadius && playerPos.z < box.max.z + playerRadius) {

                const dx1 = Math.abs(playerPos.x - (box.min.x - playerRadius));
                const dx2 = Math.abs(playerPos.x - (box.max.x + playerRadius));
                const dz1 = Math.abs(playerPos.z - (box.min.z - playerRadius));
                const dz2 = Math.abs(playerPos.z - (box.max.z + playerRadius));

                const minOverlap = Math.min(dx1, dx2, dz1, dz2);

                if (minOverlap === dx1) playerPos.x = box.min.x - playerRadius;
                else if (minOverlap === dx2) playerPos.x = box.max.x + playerRadius;
                else if (minOverlap === dz1) playerPos.z = box.min.z - playerRadius;
                else if (minOverlap === dz2) playerPos.z = box.max.z + playerRadius;
            }
        }

        // Keep player on ground (Base height)
        const baseHeight = this.height;
        playerPos.y = baseHeight;

        // Audio Only Trigger
        if (this.moveForward || this.moveBackward || this.moveLeft || this.moveRight) {
            // Step every 0.6 seconds
            this.lastStepTime += dt;
            if (this.lastStepTime > 0.6) {
                this.lastStepTime = 0;
                this.playFootstep();
            }
        } else {
            this.lastStepTime = 0.5; // Ready to step properly next time
        }

        // Flashlight flicker effect (subtle) & Battery Logic
        if (this.flashlight && this.flashlightOn) {
            // Battery Drain
            // Base intensity is ~10. Drain proportional to intensity.
            const drainFactor = this.flashlight.intensity / 10.0;
            const drain = this.baseDrain * drainFactor * dt;
            this.battery = Math.max(0, this.battery - drain);

            // Update UI
            const battEl = document.getElementById('battery-level');
            if (battEl) battEl.textContent = Math.floor(this.battery) + '%';
            if (this.battery <= 20) {
                if (battEl) battEl.style.color = 'red';
            } else {
                if (battEl) battEl.style.color = 'white';
            }

            // Die if empty
            if (this.battery <= 0) {
                this.flashlightOn = false;
                this.flashlight.visible = false;
                window.log('Battery depleted!');
            }

            // Handle manual adjustment
            if (this.adjustDim || this.adjustBright) {
                const speed = 2.0 * dt;
                const angleSpeed = 0.5 * dt;

                if (this.adjustDim) {
                    this.flashlight.intensity = Math.max(0, this.flashlight.intensity - speed * 10);
                    this.flashlight.angle = Math.max(0.1, this.flashlight.angle - angleSpeed);
                }
                if (this.adjustBright) {
                    this.flashlight.intensity = Math.min(50, this.flashlight.intensity + speed * 10);
                    this.flashlight.angle = Math.min(Math.PI / 2, this.flashlight.angle + angleSpeed);
                }
                // Log occasionally for feedback
                if (Math.random() < 0.1) window.log(`Light: Int=${this.flashlight.intensity.toFixed(1)} Ang=${this.flashlight.angle.toFixed(2)}`);
            } else {
                // Only flicker if not adjusting? Or flicker on top of base intensity. 
                // Let's modify base intensity and add flicker
                // Simplified: just flicker around the current value
                this.flashlight.intensity += (Math.random() - 0.5) * 0.5;
            }
        }
    }

    playFootstep() {
        if (!this.ctx) return;

        const t = this.ctx.currentTime;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        const filter = this.ctx.createBiquadFilter();

        // Noise buffer for texture
        const bufferSize = this.ctx.sampleRate * 0.1; // 0.1s duration
        const buffer = this.ctx.createBuffer(1, bufferSize, this.ctx.sampleRate);
        const data = buffer.getChannelData(0);
        for (let i = 0; i < bufferSize; i++) {
            data[i] = (Math.random() * 2 - 1) * 0.5;
        }
        const noise = this.ctx.createBufferSource();
        noise.buffer = buffer;

        // Filter to make it sound dull (floor/carpet)
        filter.type = 'lowpass';
        filter.frequency.setValueAtTime(400, t); // Low muffled thud

        // Envelope
        gain.gain.setValueAtTime(0.3, t);
        gain.gain.exponentialRampToValueAtTime(0.01, t + 0.1);

        // Connect
        noise.connect(filter);
        filter.connect(gain);
        gain.connect(this.ctx.destination);

        noise.start();
        noise.stop(t + 0.1);
    }
}
