import { GameLoop } from '../core/GameLoop.js';
import { GameClock } from '../core/GameClock.js';
import { GameConfig } from '../core/GameConfig.js';
import { EventBus } from '../core/EventBus.js';
import { ServiceLocator, SERVICE_KEYS } from '../core/ServiceLocator.js';
import { World } from '../ecs/World.js';
import { InputManager } from '../input/InputManager.js';
import { AudioManager } from '../audio/AudioManager.js';
import { Renderer2D, RenderSystem } from '../rendering/Renderer2D.js';
import { PhysicsEngine2D, PhysicsSystem } from '../physics/PhysicsEngine2D.js';
import { SceneManager } from '../scene/SceneManager.js';
import { GameUI } from '../ui/GameUI.js';
import { PlayerManager, SplitScreenManager } from '../multiplayer/LocalMultiplayer.js';

/* ────────────────────────────────────────────────────────────────
   NiceGameEngine — Main engine class, ties all subsystems together
──────────────────────────────────────────────────────────────── */
class NiceGameEngine {
    constructor(options) {
        var _a;
        // Core
        this.events = new EventBus();
        this._state = 'idle';
        this.canvas = options.canvas;
        this._debug = (_a = options.debug) !== null && _a !== void 0 ? _a : false;
        // Config
        this.config = new GameConfig(options.settings);
        const s = this.config.settings;
        // Core
        this.clock = new GameClock();
        this.services = new ServiceLocator();
        // ECS World
        this.world = new World();
        // Input
        this.input = new InputManager();
        // Audio
        this.audio = new AudioManager();
        // Rendering
        this.renderer = new Renderer2D(options.canvas);
        // Physics
        this.physics = new PhysicsEngine2D();
        this.physics.gravity = { ...s.physics.gravity };
        // Scene
        this.scenes = new SceneManager();
        // UI
        this.ui = new GameUI();
        this.ui.setScreenSize(s.width, s.height);
        // Multiplayer
        this.players = new PlayerManager(s.maxPlayers);
        this.splitScreen = new SplitScreenManager();
        this.splitScreen.setCanvasSize(s.width, s.height);
        // Register services
        this.services.register(SERVICE_KEYS.EVENT_BUS, this.events);
        this.services.register(SERVICE_KEYS.WORLD, this.world);
        this.services.register(SERVICE_KEYS.INPUT, this.input);
        this.services.register(SERVICE_KEYS.AUDIO, this.audio);
        this.services.register(SERVICE_KEYS.RENDERER, this.renderer);
        this.services.register(SERVICE_KEYS.CAMERA, this.renderer.camera);
        this.services.register(SERVICE_KEYS.SCENE_MANAGER, this.scenes);
        this.services.register(SERVICE_KEYS.PLAYER_MANAGER, this.players);
        // Built-in systems
        this.world.addSystem(new PhysicsSystem(this.physics));
        this.world.addSystem(new RenderSystem(this.renderer));
        // Game loop
        this.loop = new 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);
    }
}

export { NiceGameEngine };
//# sourceMappingURL=NiceGameEngine.js.map
