'use strict';

var GameLoop = require('../core/GameLoop.js');
var GameClock = require('../core/GameClock.js');
var GameConfig = require('../core/GameConfig.js');
var EventBus = require('../core/EventBus.js');
var ServiceLocator = require('../core/ServiceLocator.js');
var World = require('../ecs/World.js');
var InputManager = require('../input/InputManager.js');
var AudioManager = require('../audio/AudioManager.js');
var Renderer2D = require('../rendering/Renderer2D.js');
var PhysicsEngine2D = require('../physics/PhysicsEngine2D.js');
var SceneManager = require('../scene/SceneManager.js');
var GameUI = require('../ui/GameUI.js');
var LocalMultiplayer = require('../multiplayer/LocalMultiplayer.js');

/* ────────────────────────────────────────────────────────────────
   NiceGameEngine — Main engine class, ties all subsystems together
──────────────────────────────────────────────────────────────── */
class NiceGameEngine {
    constructor(options) {
        var _a;
        // Core
        this.events = new EventBus.EventBus();
        this._state = 'idle';
        this.canvas = options.canvas;
        this._debug = (_a = options.debug) !== null && _a !== void 0 ? _a : false;
        // Config
        this.config = new GameConfig.GameConfig(options.settings);
        const s = this.config.settings;
        // Core
        this.clock = new GameClock.GameClock();
        this.services = new ServiceLocator.ServiceLocator();
        // ECS World
        this.world = new World.World();
        // Input
        this.input = new InputManager.InputManager();
        // Audio
        this.audio = new AudioManager.AudioManager();
        // Rendering
        this.renderer = new Renderer2D.Renderer2D(options.canvas);
        // Physics
        this.physics = new PhysicsEngine2D.PhysicsEngine2D();
        this.physics.gravity = { ...s.physics.gravity };
        // Scene
        this.scenes = new SceneManager.SceneManager();
        // UI
        this.ui = new GameUI.GameUI();
        this.ui.setScreenSize(s.width, s.height);
        // Multiplayer
        this.players = new LocalMultiplayer.PlayerManager(s.maxPlayers);
        this.splitScreen = new LocalMultiplayer.SplitScreenManager();
        this.splitScreen.setCanvasSize(s.width, s.height);
        // Register services
        this.services.register(ServiceLocator.SERVICE_KEYS.EVENT_BUS, this.events);
        this.services.register(ServiceLocator.SERVICE_KEYS.WORLD, this.world);
        this.services.register(ServiceLocator.SERVICE_KEYS.INPUT, this.input);
        this.services.register(ServiceLocator.SERVICE_KEYS.AUDIO, this.audio);
        this.services.register(ServiceLocator.SERVICE_KEYS.RENDERER, this.renderer);
        this.services.register(ServiceLocator.SERVICE_KEYS.CAMERA, this.renderer.camera);
        this.services.register(ServiceLocator.SERVICE_KEYS.SCENE_MANAGER, this.scenes);
        this.services.register(ServiceLocator.SERVICE_KEYS.PLAYER_MANAGER, this.players);
        // Built-in systems
        this.world.addSystem(new PhysicsEngine2D.PhysicsSystem(this.physics));
        this.world.addSystem(new Renderer2D.RenderSystem(this.renderer));
        // Game loop
        this.loop = new GameLoop.GameLoop({
            update: (dt) => this.update(dt),
            fixedUpdate: (fixedDt) => this.fixedUpdate(fixedDt),
            render: (alpha) => this.render(alpha),
        });
        this.loop.fixedTimestep = s.physics.fixedTimestep;
    }
    get state() {
        return this._state;
    }
    get camera() {
        return this.renderer.camera;
    }
    get debug() {
        return this._debug;
    }
    set debug(v) {
        this._debug = v;
        this.renderer.debugDraw = v;
    }
    /* ── Lifecycle ──────────────────────────────────────────────── */
    async start() {
        this._state = 'loading';
        this.events.emit('engine:loading', null);
        // Init input (attaches DOM listeners)
        this.input.attach(this.canvas);
        // Init audio
        await this.audio.init();
        this._state = 'running';
        this.loop.start();
        this.events.emit('engine:started', null);
    }
    stop() {
        this.loop.stop();
        this.input.detach();
        this._state = 'idle';
        this.events.emit('engine:stopped', null);
    }
    pause() {
        if (this._state === 'running') {
            this._state = 'paused';
            this.loop.stop();
            this.clock.pause();
            this.events.emit('engine:paused', null);
        }
    }
    resume() {
        if (this._state === 'paused') {
            this._state = 'running';
            this.clock.resume();
            this.loop.start();
            this.events.emit('engine:resumed', null);
        }
    }
    destroy() {
        this.stop();
        this.world.clear();
        this.ui.clear();
        this.audio.stopAll();
        this.services.clear();
        this.events.clear();
    }
    /** Alias for destroy() — unified cleanup pattern. */
    dispose() {
        this.destroy();
    }
    /* ── Main loops ─────────────────────────────────────────────── */
    update(dt) {
        if (this._state !== 'running')
            return;
        this.clock.tick(dt);
        this.input.update();
        this.scenes.updateTransition(dt);
        this.world.update(dt);
        this.events.emit('engine:update', dt);
    }
    fixedUpdate(fixedDt) {
        if (this._state !== 'running')
            return;
        this.world.fixedUpdate(fixedDt);
        this.events.emit('engine:fixedUpdate', fixedDt);
    }
    render(alpha) {
        const ctx = this.renderer.ctx;
        if (!ctx)
            return;
        const viewports = this.splitScreen.getViewports();
        if (viewports.length <= 1) {
            this.renderer.render(this.world, alpha);
        }
        else {
            for (const vp of viewports) {
                this.splitScreen.applyViewport(ctx, vp);
                this.renderer.render(this.world, alpha);
                this.splitScreen.restoreViewport(ctx);
            }
            this.splitScreen.renderDividers(ctx);
        }
        // UI overlay (always on top, full screen)
        this.ui.render(ctx);
        this.events.emit('engine:render', alpha);
    }
}

exports.NiceGameEngine = NiceGameEngine;
//# sourceMappingURL=NiceGameEngine.js.map
