import * as THREE from 'three';
import { state } from '../state.js';
import { SceneFeature } from './SceneFeature.js';
import sceneFeatureManager from './SceneFeatureManager.js';

export class StageLasers extends SceneFeature {
    constructor() {
        super();
        this.lasers = [];
        this.pattern = 0;
        this.lastPatternChange = 0;
        this.averageLoudness = 0;
        this.activationState = 'IDLE';
        this.stateTimer = 0;
        this.initialSilenceSeconds = 10;
        this.currentCycleMode = 'RUNNING';
        this.dummyColor = new THREE.Color();
        this.areLasersVisible = true;
        sceneFeatureManager.register(this);
    }

    init() {
        // Geometry: Long thin cylinder, pivot at one end
        const length = 80;
        const geometry = new THREE.CylinderGeometry(0.03, 0.03, length, 8);
        geometry.rotateX(-Math.PI / 2); // Align with Z axis
        geometry.translate(0, 0, length / 2); // Pivot at start

        // Material: Additive blending for light beam effect
        const material = new THREE.MeshBasicMaterial({
            color: 0x00ff00,
            transparent: true,
            opacity: 0.3,
            blending: THREE.AdditiveBlending,
            depthWrite: false,
            side: THREE.DoubleSide
        });

        this.sharedGeometry = geometry;
        this.sharedMaterial = material;

        // Fixture assets
        this.fixtureGeometry = new THREE.BoxGeometry(0.2, 0.2, 0.3);
        this.fixtureMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x111111, 
            roughness: 0.7,
            metalness: 0.2
        });

        // Create Banks of Lasers
        // 1. Left
        this.createBank(new THREE.Vector3(-7, 8.2, -18), 3, 0.4, 0.3);
        // 2. Right
         this.createBank(new THREE.Vector3(7, 8.2, -18), 3, 0.4, -0.3);
        // 3. Center
        this.createBank(new THREE.Vector3(0, 8.5, -16), 8, 0.5, 0);
    }

    createBank(position, count, spacing, angleOffsetY) {
        const group = new THREE.Group();
        group.position.copy(position);
        // Rotate bank slightly to face center/audience
        group.rotation.y = angleOffsetY; 
        state.scene.add(group);

        // --- Connecting Bar ---
        const barWidth = (count * spacing) + 0.2;
        const barGeo = new THREE.BoxGeometry(barWidth, 0.1, 0.1);
        const barMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.7, metalness: 0.5 });
        const bar = new THREE.Mesh(barGeo, barMat);
        bar.position.set(0, 0, -0.25); // Behind the fixtures
        group.add(bar);

        for (let i = 0; i < count; i++) {
            const mesh = new THREE.Mesh(this.sharedGeometry, this.sharedMaterial.clone());
            // Center the bank
            const xOff = (i - (count - 1) / 2) * spacing;
            mesh.position.set(xOff, 0, 0);
            
            // Add Static Fixture
            const fixture = new THREE.Mesh(this.fixtureGeometry, this.fixtureMaterial);
            fixture.position.set(xOff, 0, -0.15);
            fixture.castShadow = true;
            group.add(fixture);

            // Add a source flare
            const flare = new THREE.Mesh(
                new THREE.SphereGeometry(0.06, 8, 8), 
                new THREE.MeshBasicMaterial({ color: 0xffffff })
            );
            mesh.add(flare);

            group.add(mesh);

            this.lasers.push({
                mesh: mesh,
                flare: flare,
                index: i,
                totalInBank: count,
                bankId: position.x < 0 ? 0 : (position.x > 0 ? 1 : 2), // 0:L, 1:R, 2:C
                staticColorIndex: Math.floor(Math.random() * 100)
            });
        }
    }

    update(deltaTime) {
        if (!state.partyStarted) {
            if (this.areLasersVisible) {
                this.lasers.forEach(l => l.mesh.visible = false);
                this.areLasersVisible = false;
            }
            return;
        }

        const time = state.clock.getElapsedTime();

        if (!state.config.lasersEnabled || state.blackoutMode) {
            if (this.areLasersVisible) {
                this.lasers.forEach(l => l.mesh.visible = false);
                this.areLasersVisible = false;
            }
            if (state.laserData) state.laserData.count = 0;
            return;
        }
        
        // --- Loudness Check ---
        let isActive = false;
        if (state.music) {
            const loudness = state.music.loudness || 0;
            // Update running average
            this.averageLoudness = THREE.MathUtils.lerp(this.averageLoudness, loudness, deltaTime * 0.2);

            if (this.activationState === 'IDLE') {
                // Wait for song to pick up before first activation
                if (time > this.initialSilenceSeconds && state.music.isLoudEnough && loudness > this.averageLoudness + 0.1) {
                    this.activationState = 'WARMUP';
                    this.stateTimer = 1.0; // Warmup duration

                    // Pick a random mode for this activation cycle (used if config is 'ANY')
                    const modes = ['SINGLE', 'RANDOM', 'RUNNING'];
                    this.currentCycleMode = modes[Math.floor(Math.random() * modes.length)];
                }
            } else if (this.activationState === 'WARMUP') {
                isActive = true;
                this.stateTimer -= deltaTime;
                if (this.stateTimer <= 0) {
                    if (state.music.beatIntensity > 0.8) {
                        this.activationState = 'ACTIVE';
                        this.stateTimer = 4.0; // Active duration
                    }
                }
            } else if (this.activationState === 'ACTIVE') {
                isActive = true;
                this.stateTimer -= deltaTime;
                if (this.stateTimer <= 0) {
                    if (state.music.beatIntensity > 0.8) {
                        this.activationState = 'FADEOUT';
                        this.stateTimer = 1.0; // Fadeout duration
                    }
                }
            } else if (this.activationState === 'FADEOUT') {
                isActive = true;
                this.stateTimer -= deltaTime;
                if (this.stateTimer <= 0) {
                    this.activationState = 'COOLDOWN';
                    this.stateTimer = 4.0; // Cooldown duration
                    isActive = false;
                }
            } else if (this.activationState === 'COOLDOWN') {
                this.stateTimer -= deltaTime;
                if (this.stateTimer <= 0) {
                    this.activationState = 'IDLE';
                }
            }
        }

        if (!isActive) {
            if (this.areLasersVisible) {
                this.lasers.forEach(l => l.mesh.visible = false);
                this.areLasersVisible = false;
            }
            return;
        }
        
        if (!this.areLasersVisible) {
            this.lasers.forEach(l => l.mesh.visible = true);
            this.areLasersVisible = true;
        }

        // --- Pattern Logic ---
        if (time - this.lastPatternChange > 8) { // Change every 8 seconds
            this.pattern = (this.pattern + 1) % 8;
            this.lastPatternChange = time;
        }

        // --- Color & Intensity ---
        const beat = state.music ? state.music.beatIntensity : 0;
        
        let intensity = 0.2 + beat * 0.6;

        // Strobe Mode: Flash rapidly when beat intensity is high
        if (beat > 0.7) {
            // Rapid on/off based on time (approx 15Hz)
            if (Math.sin(time * 100) < 0) {
                intensity = 0.05;
            } else {
                intensity = 1.0;
            }
        }

        this.lasers.forEach(l => {
            let currentIntensity = intensity;
            let flareScale = 1.0;

            if (this.activationState === 'WARMUP') {
                currentIntensity = 0;
                if (this.stateTimer > 0) {
                    flareScale = 1.0 - this.stateTimer;
                } else {
                    flareScale = 1.0 + Math.sin(time * 30) * 0.2; // Pulse while waiting for beat
                }
            } else if (this.activationState === 'FADEOUT') {
                const fade = Math.max(0, this.stateTimer / 1.0);
                currentIntensity = 0;
                flareScale = fade;
            }

            let colorHex = 0x00ff00; // Default green
            const palette = state.config.lightBarColors;
            
            let mode = state.config.laserColorMode;
            if (mode === 'ANY') {
                mode = this.currentCycleMode;
            }

            if (palette && palette.length > 0) {
                if (mode === 'SINGLE') {
                    colorHex = palette[0];
                } else if (mode === 'RANDOM') {
                    colorHex = palette[l.staticColorIndex % palette.length];
                } else if (mode === 'RUNNING') {
                    const offset = Math.floor(time * 4); // Speed of running
                    const idx = (l.index + offset) % palette.length;
                    colorHex = palette[idx];
                } else {
                    // Fallback to running if unknown
                    const idx = l.index % palette.length;
                    colorHex = palette[idx];
                }
            } else {
                // Fallback if no palette: Cycle hue
                const hue = (time * 0.1) % 1;
                this.dummyColor.setHSL(hue, 1.0, 0.5);
                colorHex = this.dummyColor.getHex();
            }

            l.mesh.material.color.set(colorHex);
            l.flare.material.color.set(colorHex);

            l.mesh.material.opacity = currentIntensity;
            l.flare.scale.setScalar(flareScale);

            // --- Movement Calculation ---
            let yaw = 0;
            let pitch = 0;
            const t = time * 2.0;
            const idx = l.index;

            switch (this.pattern) {
                case 0: // Lissajous / Figure 8
                    yaw = Math.sin(t + idx * 0.2) * 0.5;
                    pitch = Math.cos(t * 1.5 + idx * 0.2) * 0.3;
                    break;
                case 1: // Horizontal Scan / Wave
                    yaw = Math.sin(t * 2 + idx * 0.5) * 0.8;
                    pitch = Math.sin(t * 0.5) * 0.1;
                    break;
                case 2: // Tunnel / Circle
                    const offset = (Math.PI * 2 / l.totalInBank) * idx;
                    const radius = 0.4;
                    yaw = Math.cos(t + offset) * radius;
                    pitch = Math.sin(t + offset) * radius;
                    break;
                case 3: // Chaos / Random
                    yaw = Math.sin(t * 3 + idx) * 0.6;
                    pitch = Math.cos(t * 2.5 + idx * 2) * 0.4;
                    break;
                case 4: // Vertical Wave
                    yaw = 0;
                    pitch = Math.sin(t * 2 + idx * 0.3) * 0.5;
                    break;
                case 5: // Cross
                    yaw = Math.sin(t) * 0.5 * (idx % 2 === 0 ? 1 : -1);
                    pitch = Math.cos(t) * 0.2;
                    break;
                case 6: // Expanding Circle
                    const r6 = (Math.sin(t) + 1.2) * 0.3;
                    const a6 = (Math.PI * 2 / l.totalInBank) * idx + t;
                    yaw = Math.cos(a6) * r6;
                    pitch = Math.sin(a6) * r6;
                    break;
                case 7: // Fan Sweep
                    yaw = Math.sin(t) * 0.8 + ((idx / l.totalInBank) - 0.5) * 0.5;
                    pitch = 0;
                    break;
            }

            // Apply rotation
            // Default points +Z. 
            l.mesh.rotation.set(pitch, yaw, 0);
        });
    }

    onPartyEnd() {
        if (this.areLasersVisible) {
            this.lasers.forEach(l => l.mesh.visible = false);
            this.areLasersVisible = false;
        }
    }
}

new StageLasers();