import * as BABYLON from "babylonjs";
import { playSfx } from "./sfx.js";
import { checkChestRaycast, checkExitProximity, setChestHighlight } from "../game/collisions.js";
import { updateHUD, setLowTimeWarning, updateSphereMesh } from "../ui/hud.js";

const cellSize = 2;
const ROUND_TIME_SECONDS = 60;

/**
 * Register the main game loop
 */
export function registerGameLoop(scene, engine, state, callbacks) {
    let lowTimeAlertPlayed = false;
    let lastFootstepPosition = null;
    let footstepAccumulator = 0;
    let footstepElapsed = 0;

    scene.registerBeforeRender(() => {
        // Update HUD
        updateHUD(state);
        updateSphereMesh(callbacks.sphere, state.config.level);

        // Chest highlight raycasting
        if (state.runtime.runActive && callbacks.fpCamera && state.cameraMode === "fp") {
            const highlighted = checkChestRaycast(scene, callbacks.fpCamera, cellSize * 3.5);
            if (highlighted) {
                setChestHighlight(highlighted.mesh);
            } else {
                setChestHighlight(null);
            }
        }

        if (state.runtime.runActive) {
            const dt = engine.getDeltaTime() / 1000;
            state.runtime.elapsedSeconds = Math.max(0, state.runtime.elapsedSeconds - dt);

            // Low-time alert
            const isLowTime = state.runtime.elapsedSeconds < 10;
            if (isLowTime && !lowTimeAlertPlayed) {
                lowTimeAlertPlayed = true;
                playSfx("clock", 0.75);
                setLowTimeWarning(true);
            }
            if (!isLowTime && lowTimeAlertPlayed) {
                lowTimeAlertPlayed = false;
                setLowTimeWarning(false);
            }

            // Time-up check
            if (state.runtime.elapsedSeconds <= 0) {
                state.runtime.runActive = false;
                state.runtime.message = "Time up — game over.";
                playSfx("lose", 0.85);
                callbacks.onGameOver?.();
                return;
            }

            // Footstep sounds
            if (callbacks.fpCamera && callbacks.fpCamera.position && document.pointerLockElement === document.getElementById("renderCanvas")) {
                const currentPosition = callbacks.fpCamera.position;
                if (!lastFootstepPosition) {
                    lastFootstepPosition = currentPosition.clone();
                }
                const horizontalDistance = Math.hypot(
                    currentPosition.x - lastFootstepPosition.x,
                    currentPosition.z - lastFootstepPosition.z,
                );
                footstepAccumulator += horizontalDistance;
                footstepElapsed += engine.getDeltaTime();
                if (footstepAccumulator > 0.75 && footstepElapsed > 220) {
                    playSfx("step", 0.65);
                    footstepAccumulator = 0;
                    footstepElapsed = 0;
                    lastFootstepPosition = currentPosition.clone();
                }
            }

            // Exit proximity check
            if (state.runtime.hasKey && state.exitBox && callbacks.fpCamera && callbacks.fpCamera.position) {
                const pos = callbacks.fpCamera.position;
                const ex = state.exitBox.position.x;
                const ez = state.exitBox.position.z;
                const dist = Math.hypot(pos.x - ex, pos.z - ez);
                if (dist < cellSize * 0.9) {
                    playSfx("win", 0.85);
                    state.config.level += 1;
                    state.runtime.hasKey = false;
                    state.runtime.roundsCompleted += 1;
                    state.runtime.elapsedSeconds = ROUND_TIME_SECONDS;
                    state.runtime.message = `Level ${state.config.level} starting.`;
                    callbacks.onLevelComplete?.();
                }
            }
        }
    });

    return { stop: () => {} };
}

/**
 * Export constants
 */
export { ROUND_TIME_SECONDS };
