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

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

    init() {
        // --- Dimensions from room-walls.js for positioning ---
        const length = 40;
        const naveWidth = 12;
        const aisleWidth = 6;
        const totalWidth = naveWidth + 2 * aisleWidth;
        const aisleHeight = 8;
        const naveHeight = 15;

        // --- Window Properties ---
        const windowWidth = 3;
        const windowBaseHeight = 5;
        const windowArchHeight = 1.5;
        const numWindowsPerSide = 4;
        const windowSpacing = length / numWindowsPerSide;

        // --- Procedural Material ---
        const material = new THREE.MeshStandardMaterial({
            vertexColors: true, // Use colors assigned to vertices
            side: THREE.DoubleSide,
            metalness: 0.1, // Glass is not very metallic
            roughness: 0.3, // Glass is smooth
            emissive: 0x222222, // Set to white to use vertex colors for glow
            emissiveIntensity: 0.1, // Start with a base intensity
            //blending: THREE.AdditiveBlending, // Additive blending for a bright, glowing effect
        });

        const colorPalette = [
            new THREE.Color(0x6A0DAD), // Purple
            new THREE.Color(0x00008B), // Dark Blue
            new THREE.Color(0xB22222), // Firebrick Red
            new THREE.Color(0xFFD700), // Gold
            new THREE.Color(0x006400), // Dark Green
            new THREE.Color(0x8B0000), // Dark Red
            new THREE.Color(0x4B0082), // Indigo
        ];

        // --- Procedural Geometry Generation ---
        const createProceduralWindowGeometry = (mainColor) => {
            const secondColor = new THREE.Color((Math.random()), (Math.random()), (Math.random()));
            const segmentsX = 8;
            const segmentsY = 12;
            const vertices = [];
            const colors = [];
            const normals = [];

            const randomnessFactor = 0.4; // How much to vary the normals

            const addTriangle = (v1, v2, v3, isBorder = false) => {
                let segmentColor;
                const rand = Math.random();

                if (rand < 0.05) { // 5% chance for a "lead line"
                    segmentColor = secondColor.clone();
                } else if (isBorder && rand < 0.6) { // 60% chance for border segments to be the main color
                    segmentColor = mainColor.clone().offsetHSL(0, 0, -0.1); // Slightly darker border
                } else if (isBorder) { // Remaining chance for border to be an accent
                    segmentColor = colorPalette[Math.floor(Math.random() * colorPalette.length)].clone().offsetHSL(0, 0, -0.1);
                }
                else { // Inner panels
                    if (rand < 0.65) { // 65% chance (after lead lines) to be a variation of the main color
                        segmentColor = mainColor.clone();
                        // Slightly shift hue, saturation, and lightness
                        segmentColor.offsetHSL((Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.4);
                    } else if (rand < 0.8) {
                        segmentColor = secondColor.clone().offsetHSL((Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.4);
                     } else { // Remaining chance for a random accent color
                        segmentColor = new THREE.Color((Math.random()), (Math.random()), (Math.random()));
                    }
                }

                vertices.push(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z);
                colors.push(segmentColor.r, segmentColor.g, segmentColor.b, segmentColor.r, segmentColor.g, segmentColor.b, segmentColor.r, segmentColor.g, segmentColor.b);

                // Calculate the base normal for the flat triangle face
                const edge1 = new THREE.Vector3().subVectors(v2, v1);
                const edge2 = new THREE.Vector3().subVectors(v3, v1);
                const faceNormal = new THREE.Vector3().crossVectors(edge1, edge2).normalize();

                // Introduce a random vector to alter the normal
                const randomVec = new THREE.Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize();
                faceNormal.add(randomVec.multiplyScalar(randomnessFactor)).normalize();

                // Apply the same randomized normal to all 3 vertices for a faceted look
                normals.push(faceNormal.x, faceNormal.y, faceNormal.z, faceNormal.x, faceNormal.y, faceNormal.z, faceNormal.x, faceNormal.y, faceNormal.z);
            };

            // Create rectangular part
            for (let i = 0; i < segmentsX; i++) {
                for (let j = 0; j < segmentsY; j++) {
                    const x = -windowWidth / 2 + (i * windowWidth) / segmentsX;
                    const y = (j * windowBaseHeight) / segmentsY;
                    const x2 = x + windowWidth / segmentsX;
                    const y2 = y + windowBaseHeight / segmentsY;

                    const v1 = new THREE.Vector3(x, y, 0);
                    const v2 = new THREE.Vector3(x2, y, 0);
                    const v3 = new THREE.Vector3(x, y2, 0);
                    const v4 = new THREE.Vector3(x2, y2, 0);
                    const isBorder = i === 0 || i === segmentsX - 1 || j === 0;
                    addTriangle(v1, v2, v3, isBorder);
                    addTriangle(v2, v4, v3, isBorder);
                }
            }

            // Create arch part
            const archCenter = new THREE.Vector3(0, windowBaseHeight, 0);
            for (let i = 0; i < segmentsX * 2; i++) {
                const angle1 = (i / (segmentsX * 2)) * Math.PI;
                const angle2 = ((i + 1) / (segmentsX * 2)) * Math.PI;
                const v1 = archCenter;
                const v2 = new THREE.Vector3(Math.cos(angle1) * -windowWidth / 2, Math.sin(angle1) * windowArchHeight + windowBaseHeight, 0);
                const v3 = new THREE.Vector3(Math.cos(angle2) * -windowWidth / 2, Math.sin(angle2) * windowArchHeight + windowBaseHeight, 0);
                addTriangle(v1, v2, v3, true); // Treat all arch segments as part of the border
            }

            const geometry = new THREE.BufferGeometry();
            geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
            geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
            geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
            return geometry;
        };

        const createProceduralRoseWindowGeometry = (mainColor, radius) => {
            const segments = 32; // Number of radial segments
            const rings = 5;
            const vertices = [];
            const colors = [];
            const normals = [];

            const randomnessFactor = 0.4;

            const addTriangle = (v1, v2, v3, isBorder = false) => {
                let segmentColor;
                const rand = Math.random();

                if (rand < 0.05) { // 5% chance for a "lead line"
                    segmentColor = new THREE.Color(0x333333);
                } else if (isBorder && rand < 0.6) {
                    segmentColor = mainColor.clone().offsetHSL(0, 0, -0.1);
                } else if (isBorder) {
                    segmentColor = colorPalette[Math.floor(Math.random() * colorPalette.length)].clone().offsetHSL(0, 0, -0.1);
                } else {
                    if (rand < 0.85) {
                        segmentColor = mainColor.clone();
                        segmentColor.offsetHSL((Math.random() - 0.5) * 0.1, (Math.random() - 0.5) * 0.3, (Math.random() - 0.5) * 0.2);
                    } else {
                        segmentColor = colorPalette[Math.floor(Math.random() * colorPalette.length)];
                    }
                }
                vertices.push(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z);
                colors.push(segmentColor.r, segmentColor.g, segmentColor.b, segmentColor.r, segmentColor.g, segmentColor.b, segmentColor.r, segmentColor.g, segmentColor.b);
                const edge1 = new THREE.Vector3().subVectors(v2, v1);
                const edge2 = new THREE.Vector3().subVectors(v3, v1);
                const faceNormal = new THREE.Vector3().crossVectors(edge1, edge2).normalize();
                const randomVec = new THREE.Vector3(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize();
                faceNormal.add(randomVec.multiplyScalar(randomnessFactor)).normalize();
                normals.push(faceNormal.x, faceNormal.y, faceNormal.z, faceNormal.x, faceNormal.y, faceNormal.z, faceNormal.x, faceNormal.y, faceNormal.z);
            };

            for (let r = 0; r < rings; r++) {
                for (let s = 0; s < segments; s++) {
                    const angle1 = (s / segments) * Math.PI * 2;
                    const angle2 = ((s + 1) / segments) * Math.PI * 2;
                    const v1 = new THREE.Vector3(Math.cos(angle1) * (r * radius / rings), Math.sin(angle1) * (r * radius / rings), 0);
                    const v2 = new THREE.Vector3(Math.cos(angle2) * (r * radius / rings), Math.sin(angle2) * (r * radius / rings), 0);
                    const v3 = new THREE.Vector3(Math.cos(angle1) * ((r + 1) * radius / rings), Math.sin(angle1) * ((r + 1) * radius / rings), 0);
                    const v4 = new THREE.Vector3(Math.cos(angle2) * ((r + 1) * radius / rings), Math.sin(angle2) * ((r + 1) * radius / rings), 0);
                    addTriangle(v1, v2, v3, r === rings - 1);
                    addTriangle(v2, v4, v3, r === rings - 1);
                }
            }
            const geometry = new THREE.BufferGeometry();
            geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
            geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
            geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
            return geometry;
        };

        // --- Create and Place Windows ---
        const createAndPlaceWindow = (position, rotationY) => {
            // Pick a main color for this entire window
            const mainColor = colorPalette[Math.floor(Math.random() * colorPalette.length)];
            const geometry = createProceduralWindowGeometry(mainColor); // Generate unique geometry for each window
            const windowMesh = new THREE.Mesh(geometry, material);
            windowMesh.position.copy(position);
            windowMesh.rotation.y = rotationY;
            state.scene.add(windowMesh);
            this.windows.push(windowMesh);
        };

        for (let i = 0; i < numWindowsPerSide; i++) {
            const z = -length / 2 + windowSpacing * (i + 0.5);
            const y = 0; // Place them starting from the floor

            // Left side
            createAndPlaceWindow(new THREE.Vector3(-totalWidth / 2 + 0.01, y, z), Math.PI / 2);
            // Right side
            createAndPlaceWindow(new THREE.Vector3(totalWidth / 2 - 0.01, y, z), -Math.PI / 2);
        }

        // --- Add Windows to the Nave/Clerestory Walls ---
        for (let i = 0; i < numWindowsPerSide * 2; i++) {
            const z = -length / 2 + windowSpacing / 2 * (i + 0.5);
            const y = aisleHeight + (naveHeight - aisleHeight - (windowBaseHeight + windowArchHeight)) / 2; // Center them vertically in the clerestory

            // Left side of Nave
            createAndPlaceWindow(new THREE.Vector3(-naveWidth / 2 + 0.01, y, z), Math.PI / 2);
            // Right side of Nave
            createAndPlaceWindow(new THREE.Vector3(naveWidth / 2 - 0.01, y, z), -Math.PI / 2);
        }

        // --- Add Huge Rose Window behind the stage ---
        const roseWindowRadius = naveWidth / 2 - 1; // Almost as wide as the nave
        const roseWindowMainColor = colorPalette[Math.floor(Math.random() * colorPalette.length)];
        const roseWindowGeo = createProceduralRoseWindowGeometry(roseWindowMainColor, roseWindowRadius);
        const roseWindowMesh = new THREE.Mesh(roseWindowGeo, material);
        roseWindowMesh.position.set(0, naveHeight - 2, -length / 2 + 0.05);
        state.scene.add(roseWindowMesh);
        this.windows.push(roseWindowMesh);

    }

    update(deltaTime) {
        // Add a subtle pulsing glow to the windows
        let intensity = 0.15; // Base intensity

        // --- Music Visualization ---
        if (state.music) {
            const beatPulse = state.music.beatIntensity * 0.3;
            intensity += beatPulse;
        }
        
        // To make the glow match the vertex colors, we set the emissive color to white
        // and modulate its intensity. The final glow color will be vertexColor * emissive * emissiveIntensity.
        this.windows.forEach(w => {
            w.material.emissiveIntensity = intensity;
        });
    }
}

new StainedGlass();