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

export class RoseWindowLightshafts extends SceneFeature {
    constructor() {
        super();
        this.shafts = [];
        sceneFeatureManager.register(this);
    }

    init() {
        // --- Dimensions for positioning ---
        const length = 40;
        const naveWidth = 12;
        const naveHeight = 15;
        const stageDepth = 5;
        const stageWidth = naveWidth - 1;

        const roseWindowRadius = naveWidth / 2 - 2;
        const roseWindowCenter = new THREE.Vector3(0, naveHeight, -length / 2 - 1.1);

        // --- Procedural Noise Texture for Light Shafts ---
        const createNoiseTexture = () => {
            const width = 128;
            const height = 512;
            const canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            const context = canvas.getContext('2d');
            const imageData = context.createImageData(width, height);
            const data = imageData.data;

            for (let i = 0; i < data.length; i += 4) {
                // Create vertical streaks of noise
                const y = Math.floor((i / 4) / width);
                const noise = Math.pow(Math.random(), 2.5) * (1 - y / height) * 255;
                data[i] = noise;     // R
                data[i + 1] = noise; // G
                data[i + 2] = noise; // B
                data[i + 3] = 255;   // A
            }
            context.putImageData(imageData, 0, 0);
            return new THREE.CanvasTexture(canvas);
        };

        const baseMaterial = new THREE.MeshBasicMaterial({
            //map: texture,
            blending: THREE.AdditiveBlending,
            transparent: true,
            depthWrite: false,
            opacity: 1.0,
            color: 0x88aaff, // Give the light a cool blueish tint
        });

        // --- Create multiple thin light shafts ---
        const numShafts = 16;
        for (let i = 0; i < numShafts; i++) {
            const texture = createNoiseTexture();
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            const material = baseMaterial.clone(); // Each shaft needs its own material for individual opacity
            material.map = texture;

            const startAngle = Math.random() * Math.PI * 2;
            const startRadius = Math.random() * roseWindowRadius;
            const startPoint = new THREE.Vector3(
                roseWindowCenter.x + Math.cos(startAngle) * startRadius,
                roseWindowCenter.y + Math.sin(startAngle) * startRadius,
                roseWindowCenter.z
            );

            // Define a linear path on the floor for the beam to travel
            const floorStartPoint = new THREE.Vector3(
                (Math.random() - 0.5) * stageWidth * 0.75,
                0,
                -length / 2 + Math.random() * 8 + 0
            );
            const floorEndPoint = new THREE.Vector3(
                (Math.random() - 0.5) * stageWidth * 0.75,
                0,
                -length / 2 + Math.random() * 8 + 3
            );

            const distance = startPoint.distanceTo(floorStartPoint);
            const geometry = new THREE.CylinderGeometry(0.01, 0.5 + Math.random() * 0.5, distance, 16, 1, true);
            const lightShaft = new THREE.Mesh(geometry, material);

            state.scene.add(lightShaft);
            this.shafts.push({
                mesh: lightShaft,
                startPoint: startPoint, // The stationary point in the window
                endPoint: floorStartPoint.clone(), // The current position of the beam on the floor
                floorStartPoint: floorStartPoint, // The start of the sweep path
                floorEndPoint: floorEndPoint, // The end of the sweep path
                moveSpeed: 0.01 + Math.random() * 0.5, // Each shaft has a different speed
                // No 'state' needed anymore
            });
        }
    }

    update(deltaTime) {
        const baseOpacity = 0.1;

        this.shafts.forEach(shaft => {
            const { mesh, startPoint, endPoint, floorStartPoint, floorEndPoint, moveSpeed } = shaft;

            // Animate texture for dust motes
            mesh.material.map.offset.y += deltaTime * 0.004;
            mesh.material.map.offset.x -= deltaTime * 0.02;

            if (mesh.material.map.offset.y >= 0.5) {
                mesh.material.map.offset.y -= 0.5;
            }
            if (mesh.material.map.offset.x <= 0.0) {
                mesh.material.map.offset.x += 1.0;
            }

            // --- Movement Logic ---
            const pathDirection = floorEndPoint.clone().sub(floorStartPoint).normalize();
            const pathLength = floorStartPoint.distanceTo(floorEndPoint);
            
            // Move the endpoint along its path
            endPoint.add(pathDirection.clone().multiplyScalar(moveSpeed * deltaTime));

            const currentDistance = floorStartPoint.distanceTo(endPoint);

            if (currentDistance >= pathLength) {
                // Reached the end, reset to the start
                endPoint.copy(floorStartPoint);
            }

            // --- Opacity based on Progress ---
            const progress = Math.min(currentDistance / pathLength, 1.0);
            // Use a sine curve to fade in at the start and out at the end
            const fadeOpacity = Math.sin(progress * Math.PI) * baseOpacity;

            // --- Update Mesh Position and Orientation ---
            const distance = startPoint.distanceTo(endPoint);
            mesh.scale.y = -distance/5;
            mesh.position.lerpVectors(startPoint, endPoint, 0.5);

            const quaternion = new THREE.Quaternion();
            const cylinderUp = new THREE.Vector3(0, 1, 0);
            const direction = new THREE.Vector3().subVectors(endPoint, startPoint).normalize();
            quaternion.setFromUnitVectors(cylinderUp, direction);
            mesh.quaternion.copy(quaternion);

            // --- Music Visualization ---
            const beatPulse = state.music ? state.music.beatIntensity * 0.05 : 0;
            mesh.material.opacity = fadeOpacity + beatPulse;
        });
    }
}

new RoseWindowLightshafts();