import * as THREE from 'three';
import { state } from '../state.js';
import { SceneFeature } from './SceneFeature.js';
import sceneFeatureManager from './SceneFeatureManager.js';
const guestTextureUrls = [
    '/textures/guest1.png',
    '/textures/guest2.png',
    '/textures/guest3.png',
    '/textures/guest4.png',
];

// --- Scene dimensions for positioning ---
const stageHeight = 1.5;
const stageDepth = 5;
const length = 44;

// --- Billboard Properties ---
const guestHeight = 2.5;
const guestWidth = 2.5;

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

    async init() {
        const processTexture = (texture) => {
            const image = texture.image;
            const canvas = document.createElement('canvas');
            canvas.width = image.width;
            canvas.height = image.height;
            const context = canvas.getContext('2d');
            context.drawImage(image, 0, 0);
            const keyPixelData = context.getImageData(0, 0, 1, 1).data;
            const keyColor = { r: keyPixelData[0], g: keyPixelData[1], b: keyPixelData[2] };
            const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
            const data = imageData.data;
            const threshold = 20;
            for (let i = 0; i < data.length; i += 4) {
                const r = data[i], g = data[i + 1], b = data[i + 2];
                const distance = Math.sqrt(Math.pow(r - keyColor.r, 2) + Math.pow(g - keyColor.g, 2) + Math.pow(b - keyColor.b, 2));
                if (distance < threshold) data[i + 3] = 0;
            }
            context.putImageData(imageData, 0, 0);
            return new THREE.CanvasTexture(canvas);
        };

        const materials = await Promise.all(guestTextureUrls.map(async (url) => {
            const texture = await state.loader.loadAsync(url);
            const processedTexture = processTexture(texture);
            return new THREE.MeshStandardMaterial({
                map: processedTexture,
                side: THREE.DoubleSide,
                alphaTest: 0.5,
                roughness: 0.7,
                metalness: 0.1,
            });
        }));

        const createGuests = () => {
            const geometry = new THREE.PlaneGeometry(guestWidth, guestHeight);
            const numGuests = 80;

            for (let i = 0; i < numGuests; i++) {
                const material = materials[i % materials.length];
                const guest = new THREE.Mesh(geometry, material);
                const pos = new THREE.Vector3(
                    (Math.random() - 0.5) * 10,
                    guestHeight / 2,
                    (Math.random() * 20) - 2 // Position them in the main hall
                );
                guest.visible = false; // Start invisible
                guest.position.copy(pos);
                state.scene.add(guest);

                this.guests.push({
                    mesh: guest,
                    state: 'WAITING',
                    targetPosition: pos.clone(),
                    waitStartTime: 0,
                    waitTime: 3 + Math.random() * 4, // Wait longer: 3-7 seconds
                    isMirrored: false,
                    canChangePose: true,
                    isJumping: false,
                    jumpStartTime: 0,
                });
            }
        };

        createGuests();
    }

    update(deltaTime) {
        if (this.guests.length === 0 || !state.partyStarted) return;

        const cameraPosition = new THREE.Vector3();
        state.camera.getWorldPosition(cameraPosition);

        const time = state.clock.getElapsedTime();
        const moveSpeed = 1.0; // Move slower
        const movementArea = { x: 10, z: 20, y: 0, centerZ: -4 };
        const jumpChance = 0.05; // Jump way more
        const jumpDuration = 0.5;
        const jumpHeight = 0.1;
        const jumpVariance = 0.5;

        this.guests.forEach(guestObj => {
            const { mesh } = guestObj;
            mesh.lookAt(cameraPosition.x, mesh.position.y, cameraPosition.z);

            // --- Mirroring on Beat ---
            if (state.music) {
                if (state.music.beatIntensity > 0.8 && guestObj.canChangePose) {
                    guestObj.isMirrored = Math.random() < 0.5;
                    mesh.material.map.repeat.x = guestObj.isMirrored ? -1 : 1;
                    mesh.material.map.offset.x = guestObj.isMirrored ? 1 : 0;
                    guestObj.canChangePose = false;
                } else if (state.music.beatIntensity < 0.2) {
                    guestObj.canChangePose = true;
                }
            }

            if (guestObj.state === 'WAITING') {
                if (time > guestObj.waitStartTime + guestObj.waitTime) {
                    const newTarget = new THREE.Vector3(
                        (Math.random() - 0.5) * movementArea.x,
                        movementArea.y + guestHeight / 2,
                        movementArea.centerZ + (Math.random() - 0.5) * movementArea.z
                    );
                    guestObj.targetPosition = newTarget;
                    guestObj.state = 'MOVING';
                }
            } else if (guestObj.state === 'MOVING') {
                const distance = mesh.position.distanceTo(guestObj.targetPosition);
                if (distance > 0.1) {
                    const direction = guestObj.targetPosition.clone().sub(mesh.position).normalize();
                    mesh.position.add(direction.multiplyScalar(moveSpeed * deltaTime));
                } else {
                    guestObj.state = 'WAITING';
                    guestObj.waitStartTime = time;
                    guestObj.waitTime = 3 + Math.random() * 4;
                }
            }

            if (guestObj.isJumping) {
                const jumpProgress = (time - guestObj.jumpStartTime) / jumpDuration;
                if (jumpProgress < 1) {
                    const baseHeight = movementArea.y + guestHeight / 2;
                    mesh.position.y = baseHeight + Math.sin(jumpProgress * Math.PI) * guestObj.jumpHeight;
                } else {
                    guestObj.isJumping = false;
                    mesh.position.y = movementArea.y + guestHeight / 2;
                }
            } else {
                let currentJumpChance = jumpChance * deltaTime; // Base chance over time
                if (state.music && state.music.isLoudEnough && state.music.beatIntensity > 0.8) {
                    currentJumpChance = 0.1; // High, fixed chance on the beat
                }

                if (Math.random() < currentJumpChance) {
                    guestObj.isJumping = true;
                    guestObj.jumpHeight = jumpHeight + Math.random() * jumpVariance;
                    guestObj.jumpStartTime = time;
                }
            }
        });
    }

    onPartyStart() {
        const stageFrontZ = -40 / 2 + 5 + 5; // In front of the stage
        this.guests.forEach((guestObj, index) => {
            guestObj.mesh.visible = true;
            // Rush to the stage
            guestObj.state = 'MOVING';
            if (index % 2 === 0) {
                guestObj.targetPosition.z = stageFrontZ + (Math.random() - 0.5) * 5;
            }
        });
    }

    onPartyEnd() {
        this.guests.forEach(guestObj => {
            guestObj.isJumping = false;
            guestObj.state = 'WAITING';
        });
    }
}

new PartyGuests();