import * as THREE from 'three';

const FRAME_DEPTH = 0.05;
const TRANSITION_DURATION = 5000;
const IMAGE_CHANGE_CHANCE = 0.0001;

export class PictureFrame {
    constructor(scene, { position, width, height, imageUrls, rotationY = 0 }) {
        if (!imageUrls || imageUrls.length === 0) {
            throw new Error('PictureFrame requires at least one image URL in the imageUrls array.');
        }

        this.scene = scene;
        this.mesh = this._createPictureFrame(width, height, imageUrls, 0.05);

        this.mesh.position.copy(position);
        this.mesh.rotation.y = rotationY;

        this.isTransitioning = false;
        this.transitionStartTime = 0;

        this.scene.add(this.mesh);
    }

    _createPictureFrame(width, height, imageUrls, frameThickness) {
        const paintingGroup = new THREE.Group();

        // 1. Create the wooden frame
        const frameMaterial = new THREE.MeshPhongMaterial({ color: 0x8B4513 }); // SaddleBrown

        const topFrame = new THREE.Mesh(new THREE.BoxGeometry(width + 2 * frameThickness, frameThickness, FRAME_DEPTH), frameMaterial);
        topFrame.position.y = height / 2 + frameThickness / 2;
        topFrame.castShadow = true;
        topFrame.receiveShadow = true;
        paintingGroup.add(topFrame);

        const bottomFrame = new THREE.Mesh(new THREE.BoxGeometry(width + 2 * frameThickness, frameThickness, FRAME_DEPTH), frameMaterial);
        bottomFrame.position.y = -height / 2 - frameThickness / 2;
        bottomFrame.castShadow = true;
        bottomFrame.receiveShadow = true;
        paintingGroup.add(bottomFrame);

        const leftFrame = new THREE.Mesh(new THREE.BoxGeometry(frameThickness, height, FRAME_DEPTH), frameMaterial);
        leftFrame.position.x = -width / 2 - frameThickness / 2;
        leftFrame.castShadow = true;
        leftFrame.receiveShadow = true;
        paintingGroup.add(leftFrame);

        const rightFrame = new THREE.Mesh(new THREE.BoxGeometry(frameThickness, height, FRAME_DEPTH), frameMaterial);
        rightFrame.position.x = width / 2 + frameThickness / 2;
        rightFrame.castShadow = true;
        rightFrame.receiveShadow = true;
        paintingGroup.add(rightFrame);

        // 2. Create the picture canvases with textures
        const textureLoader = new THREE.TextureLoader();
        this.textures = imageUrls.map(url => textureLoader.load(url));
        this.currentTextureIndex = 0;

        const pictureGeometry = new THREE.PlaneGeometry(width, height);

        // Create two picture planes for cross-fading
        this.pictureBack = new THREE.Mesh(pictureGeometry, new THREE.MeshPhongMaterial({ map: this.textures[this.currentTextureIndex] }));
        this.pictureBack.position.z = 0.001;
        this.pictureBack.receiveShadow = true;
        paintingGroup.add(this.pictureBack);

        this.pictureFront = new THREE.Mesh(pictureGeometry, new THREE.MeshPhongMaterial({ map: this.textures[this.currentTextureIndex], transparent: true, opacity: 0 }));
        this.pictureFront.position.z = 0.003; // Place slightly in front to avoid z-fighting
        this.pictureFront.receiveShadow = true;
        paintingGroup.add(this.pictureFront);

        return paintingGroup;
    }

    setPicture(index) {
        if (this.isTransitioning || index === this.currentTextureIndex || index < 0 || index >= this.textures.length) {
            return;
        }

        this.isTransitioning = true;
        this.transitionStartTime = Date.now();

        // Front plane fades in with the new texture
        this.pictureFront.material.map = this.textures[index];
        this.pictureFront.material.opacity = 0;

        this.nextTextureIndex = index;
    }

    nextPicture() {
        this.setPicture((this.currentTextureIndex + 1) % this.textures.length);
    }

    update() {
        if (!this.isTransitioning) {
            if (Math.random() > 1.0 - IMAGE_CHANGE_CHANCE) {
                this.nextPicture();
            }
            return;
        }

        const elapsedTime = Date.now() - this.transitionStartTime;
        const progress = Math.min(elapsedTime / TRANSITION_DURATION, 1.0);
        this.pictureFront.material.opacity = progress;

        if (progress >= 1.0) {
            this.isTransitioning = false;
            this.currentTextureIndex = this.nextTextureIndex;

            // Reset for next transition
            this.pictureBack.material.map = this.textures[this.currentTextureIndex];
            this.pictureFront.material.opacity = 0;
        }
    }
}
