import * as THREE from 'three';
import { updateVcrDisplay } from '../scene/vcr-display.js';
import { state } from '../state.js';
import { updateScreenEffect } from '../scene/magic-mirror.js'
import { updateCauldron } from '../scene/cauldron.js';
import { updateFire } from '../scene/fireplace.js';
import { updateRats } from '../scene/rat.js';
import { updateLectern } from '../scene/lectern.js';

function updateCamera() {
    const globalTime = Date.now() * 0.00003;
    const lookAtTime = Date.now() * 0.00005;

    const camAmplitude = 0.9;
    const lookAmplitude = 0.4;

    // Base Camera Position in front of the TV
    const baseX = -0.3;
    const baseY = 1.5;
    const baseZ = 1.9;

    // Base LookAt target (Center of the screen)
    const baseTargetX = -0.2;
    const baseTargetY = 1.6;
    const baseTargetZ = -0.3;

    // Camera Position Offsets (Drift)
    const camOffsetX = Math.sin(globalTime * 3.1) * camAmplitude;
    const camOffsetY = Math.cos(globalTime * 2.5) * camAmplitude * 0.4;
    const camOffsetZ = Math.cos(globalTime * 3.2) * camAmplitude * 1.2;

    state.camera.position.x = baseX + camOffsetX;
    state.camera.position.y = baseY + camOffsetY;
    state.camera.position.z = baseZ + camOffsetZ;

    // LookAt Target Offsets (Subtle Gaze Shift)
    const lookOffsetX = Math.sin(lookAtTime * 1.5) * lookAmplitude * 4;
    const lookOffsetY = Math.cos(lookAtTime * 1.2) * lookAmplitude;

    // Apply lookAt to the subtly shifted target
    state.camera.lookAt(baseTargetX + lookOffsetX, baseTargetY + lookOffsetY, baseTargetZ);
}

function updateLampFlicker() {
    const flickerChance = 0.995;
    const restoreRate = 0.15;

    if (state.candleLight) {
        const elapsedTime = state.clock.getElapsedTime();
        const flickerSpeed = 20;
        const flickerAmount = 0.05;
        // Make the candle flicker
        state.candleLight.intensity = state.originalLampIntensity + Math.sin(elapsedTime * flickerSpeed) * flickerAmount;
    }
}

function updateScreenLight() {
    if (state.isVideoLoaded && state.screenLight.intensity > 0) {
        const pulseTarget = state.originalScreenIntensity + (Math.random() - 0.5) * state.screenIntensityPulse;
        state.screenLight.intensity = THREE.MathUtils.lerp(state.screenLight.intensity, pulseTarget, 0.1);

        const lightTime = Date.now() * 0.0001;
        const radius = 0.01;
        const centerX = 0;
        const centerY = 1.5;

        state.screenLight.position.x = centerX + Math.cos(lightTime) * radius;
        state.screenLight.position.y = centerY + Math.sin(lightTime * 1.5) * radius * 0.5; // Slightly different freq for Y
    }
}

function updateShaderTime() {
    if (state.tvScreen && state.tvScreen.material.uniforms && state.tvScreen.material.uniforms.u_time) {
        state.tvScreen.material.uniforms.u_time.value = state.clock.getElapsedTime();
    }
}

function updateVideo() {
    if (state.videoTexture) {
        state.videoTexture.needsUpdate = true;
    }
}

function updateBooks() {
    const LEVITATE_CHANCE = 0.0003; // Chance for a resting book to start levitating per frame
    const LEVITATE_DURATION_MIN = 100; // frames
    const LEVITATE_DURATION_MAX = 300; // frames
    const LEVITATE_AMPLITUDE = 0.02; // Max vertical displacement
    const LEVITATE_SPEED_FACTOR = 0.03; // Speed of oscillation
    const START_RATE = 0.05; // How quickly a book starts to levitate
    const RETURN_RATE = 0.1; // How quickly a book returns to original position
    const START_DURATION = 120; // frames for the starting transition
    const levitation = state.bookLevitation;

    // Manage the global levitation state
    if (levitation.state === 'resting') {
        if (Math.random() < LEVITATE_CHANCE) {
            levitation.state = 'starting';
            levitation.timer = START_DURATION;
        }
    } else if (levitation.state === 'starting') {
        levitation.timer--;
        if (levitation.timer <= 0) {
            levitation.state = 'levitating';
            levitation.timer = LEVITATE_DURATION_MIN + Math.random() * (LEVITATE_DURATION_MAX - LEVITATE_DURATION_MIN);
        }
    } else if (levitation.state === 'levitating') {
        levitation.timer--;
        if (levitation.timer <= 0) {
            levitation.state = 'returning';
        }
    }

    // Animate books based on the global state
    let allBooksReturned = true;
    state.books.forEach(book => {
        const data = book.userData;

        if (levitation.state === 'starting') {
            allBooksReturned = false;
            book.position.y = THREE.MathUtils.lerp(book.position.y, data.originalY + LEVITATE_AMPLITUDE/2, START_RATE);
            data.oscillationTime = 0;
        } else if (levitation.state === 'levitating') {
            allBooksReturned = false;
            data.oscillationTime += LEVITATE_SPEED_FACTOR;
            data.levitateOffset = Math.sin(data.oscillationTime) * LEVITATE_AMPLITUDE;
            book.position.y = data.originalY + data.levitateOffset + LEVITATE_AMPLITUDE/2;
        } else if (levitation.state === 'returning') {
            book.position.y = THREE.MathUtils.lerp(book.position.y, data.originalY, RETURN_RATE);
            data.levitateOffset = book.position.y - data.originalY;

            if (Math.abs(data.levitateOffset) > 0.001) {
                allBooksReturned = false;
            }
        }
    });

    if (levitation.state === 'returning' && allBooksReturned) {
        levitation.state = 'resting';
    }
}

function updatePictureFrame() {
    state.pictureFrames.forEach((pictureFrame) => {
        pictureFrame.update();
    });
}

// --- Animation Loop ---
export function animate() {
    requestAnimationFrame(animate);

    state.effectsManager.update();
    updateCamera();
    updateLampFlicker();
    updateScreenLight();
    updateVideo();
    updateShaderTime();
    updateBooks();
    updatePictureFrame();
    updateScreenEffect();
    updateFire();
    updateCauldron();
    updateLectern();
    updateRats();

    // RENDER!
    state.renderer.render(state.scene, state.camera);
}

// --- Window Resize Handler ---
export function onWindowResize() {
    state.camera.aspect = window.innerWidth / window.innerHeight;
    state.camera.updateProjectionMatrix();
    state.renderer.setSize(window.innerWidth, window.innerHeight);
}