import * as BABYLON from "babylonjs";
import { sharedState } from "./game/state.js";
import { generateMazeGrid, findDeadEnds } from "./game/maze.js";
import { isWalkableCell } from "./game/grid.js";
import { playSfx, primeSfx } from "./game/sfx.js";
import { initializeScene, startRenderLoop } from "./game/scene-init.js";
import { createCameras, switchCameraMode, updateOverviewCameraForMaze, attachCamera } from "./game/camera-manager.js";
import { setupInputHandlers } from "./controls/input-handler.js";
import { buildLevelFromGrid, placeChestsOnDeadEnds, placeExit, spawnCameraAt, clearLevelMeshes } from "./game/level-generator.js";
import { registerGameLoop, ROUND_TIME_SECONDS } from "./game/game-loop.js";
import { showGameOverScreen, hideGameOverScreen, showStartScreen, hideStartScreen } from "./game/screen-manager.js";
import { checkChestRaycast, setChestHighlight } from "./game/collisions.js";

// DOM elements
const canvas = document.getElementById("renderCanvas");
const p5GameOverPanel = document.getElementById("p5-game-over-panel");
const p5StartPanel = document.getElementById("p5-start-panel");
const controlPanelSection = document.getElementById("control-panel-section");

// Initialize Babylon.js
const { engine, scene } = initializeScene(canvas);
const { fpCamera, overviewCamera } = createCameras(scene, canvas);

// Initialize central sphere (visual indicator)
const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2 }, scene);
sphere.isVisible = false;
const sphereMaterial = new BABYLON.StandardMaterial("sphereMaterial", scene);
sphereMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.55, 0.95);
sphereMaterial.emissiveColor = new BABYLON.Color3(0.05, 0.12, 0.2);
sphere.material = sphereMaterial;

// Game state extensions
sharedState.gameOverActive = false;
sharedState.cameraMode = "fp";
sharedState.chestMap = new Map();
sharedState.keyChestKey = null;
sharedState.exitBox = null;
sharedState.exitGridPos = null;
sharedState.spawnGridPos = null;
sharedState.highlightedChest = null;

// Attach first-person camera by default
attachCamera(scene, fpCamera, canvas);

let levelMeshes = [];
let controlsVisible = false;

/**
 * Generate a new level
 */
async function generateLevel() {
    hideGameOverScreen(sharedState);
    const cfg = sharedState.config;
    const seed = cfg.seed;
    const roundScale = Math.max(0, cfg.level - 1);
    const w = Math.max(9, cfg.mazeWidth + roundScale * 2);
    const h = Math.max(9, cfg.mazeHeight + roundScale * 2);
    const chestCount = Math.max(1, cfg.minChestDeadEnds + roundScale);
    
    const grid = generateMazeGrid(w, h, seed + cfg.level);
    const dead = findDeadEnds(grid);
    
    clearLevelMeshes(levelMeshes, sharedState);
    buildLevelFromGrid(scene, grid, sharedState, levelMeshes);
    placeChestsOnDeadEnds(scene, grid, dead, chestCount, seed + cfg.level, sharedState, levelMeshes);
    placeExit(scene, grid, seed + cfg.level, sharedState, levelMeshes);
    spawnCameraAt(scene, grid, fpCamera, sharedState);
    updateOverviewCameraForMaze(overviewCamera, w, h);

    const placementValid =
        !!sharedState.exitGridPos &&
        !!sharedState.spawnGridPos &&
        isWalkableCell(grid, sharedState.exitGridPos.x, sharedState.exitGridPos.y) &&
        isWalkableCell(grid, sharedState.spawnGridPos.x, sharedState.spawnGridPos.y) &&
        !(sharedState.exitGridPos.x === sharedState.spawnGridPos.x && sharedState.exitGridPos.y === sharedState.spawnGridPos.y);

    if (!placementValid) {
        sharedState.runtime.message = `Placement warning: spawn/exit invalid on level ${cfg.level}.`;
        console.warn("Invalid spawn/exit placement", { exitGridPos: sharedState.exitGridPos, spawnGridPos: sharedState.spawnGridPos });
    } else {
        sharedState.runtime.message = `Level ${cfg.level} generated (spawn ${sharedState.spawnGridPos.x},${sharedState.spawnGridPos.y} / exit ${sharedState.exitGridPos.x},${sharedState.exitGridPos.y}).`;
    }
}

/**
 * Start run from start screen
 */
function startRunFromStartScreen() {
    hideStartScreen(sharedState);
    sharedState.runtime.runActive = true;
    sharedState.runtime.hasKey = false;
    sharedState.runtime.roundsCompleted = 0;
    sharedState.runtime.elapsedSeconds = ROUND_TIME_SECONDS;
    sharedState.runtime.message = "Game started.";
    sharedState.config.level = 1;
    generateLevel();
    primeSfx();
    playSfx("click", 0.7);
}

/**
 * Restart from game-over
 */
function restartRunFromGameOver() {
    sharedState.runtime.runActive = true;
    sharedState.runtime.hasKey = false;
    sharedState.runtime.roundsCompleted = 0;
    sharedState.runtime.elapsedSeconds = ROUND_TIME_SECONDS;
    sharedState.runtime.message = "Run restarted.";
    sharedState.config.level = 1;
    hideGameOverScreen(sharedState);
    generateLevel();
}

/**
 * Toggle debug controls panel
 */
function toggleControlsPanel() {
    controlsVisible = !controlsVisible;
    if (controlPanelSection) {
        controlPanelSection.hidden = !controlsVisible;
    }
}

// Setup input handlers
setupInputHandlers(canvas, sharedState, {
    getCameraMode: () => sharedState.cameraMode,
    isGameOverActive: () => sharedState.gameOverActive,
    isStartPanelVisible: () => p5StartPanel && !p5StartPanel.hidden,
    onDebugToggle: toggleControlsPanel,
    onRestart: restartRunFromGameOver,
    onStartGame: startRunFromStartScreen,
    onCameraToggle: () => {
        switchCameraMode(scene, canvas, fpCamera, overviewCamera, sharedState);
    },
    setupScenePointerObserver: () => {
        scene.onPointerObservable.add((pi) => {
            if (pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) return;
            if (!sharedState.runtime.runActive || sharedState.gameOverActive) return;
            
            const pick = scene.pick(scene.pointerX, scene.pointerY);
            if (!pick || !pick.hit || !pick.pickedMesh) return;
            
            const m = pick.pickedMesh;
            if (!m.name.startsWith('chest_')) return;
            
            const coords = m.name.split('_').slice(1).join(',');
            const entry = sharedState.chestMap.get(coords);
            if (!entry) return;
            
            if (entry.opened) {
                primeSfx();
                playSfx("chestClose", 0.8);
                playSfx("lose", 0.85);
                sharedState.runtime.runActive = false;
                sharedState.runtime.message = 'Opened chest again — game over.';
                showGameOverScreen(sharedState);
                return;
            }
            
            primeSfx();
            playSfx("chestOpen", 0.8);
            entry.opened = true;
            if (coords === sharedState.keyChestKey) {
                sharedState.runtime.hasKey = true;
                playSfx("key", 0.85);
                sharedState.runtime.message = 'You found the key! Find the exit.';
            } else {
                sharedState.runtime.message = 'This chest was empty.';
            }
        });
    }
});

// Register game loop
registerGameLoop(scene, engine, sharedState, {
    sphere,
    fpCamera,
    onGameOver: () => {
        showGameOverScreen(sharedState);
    },
    onLevelComplete: () => {
        generateLevel();
    }
});

// Start render loop
startRenderLoop(engine, scene);

// Expose API for other modules
window.mazeGameApi = { generateLevel };

// Initialize start screen on page load
window.addEventListener("load", () => {
    showStartScreen(sharedState);
});

// Export shared state for p5 to use
export { sharedState };
