'use strict';

var EventBus = require('../core/EventBus.js');

/* ────────────────────────────────────────────────────────────────
   SceneManager — Scene lifecycle, transitions, serialization
──────────────────────────────────────────────────────────────── */
/* ── SceneManager ─────────────────────────────────────────────── */
class SceneManager {
    constructor() {
        this.events = new EventBus.EventBus();
        this.scenes = new Map();
        this.prefabs = new Map();
        this._currentId = null;
        this._loading = false;
        this._transition = null;
    }
    get currentSceneId() {
        return this._currentId;
    }
    get isLoading() {
        return this._loading;
    }
    get transition() {
        if (!this._transition)
            return null;
        return {
            progress: Math.min(1, this._transition.elapsed / (this._transition.duration / 2)),
            phase: this._transition.phase,
        };
    }
    /* ── Scene registration ─────────────────────────────────────── */
    register(config) {
        this.scenes.set(config.id, config);
    }
    unregister(id) {
        this.scenes.delete(id);
    }
    has(id) {
        return this.scenes.has(id);
    }
    get registeredScenes() {
        return Array.from(this.scenes.keys());
    }
    /* ── Scene switching ────────────────────────────────────────── */
    async loadScene(id, world, transition = { type: 'none', duration: 0 }) {
        const config = this.scenes.get(id);
        if (!config)
            throw new Error(`Scene "${id}" not registered.`);
        this._loading = true;
        this.events.emit('scene:loading', id);
        // Start transition out
        if (transition.type !== 'none' && transition.duration > 0) {
            this._transition = {
                type: transition.type,
                duration: transition.duration,
                elapsed: 0,
                phase: 'out',
            };
            // Wait for half the transition
            await sleep(transition.duration * 500);
        }
        // Clear old world
        if (this._currentId) {
            this.events.emit('scene:unload', this._currentId);
        }
        world.clear();
        // Setup new scene
        await config.setup(world);
        this._currentId = id;
        // Transition in
        if (this._transition) {
            this._transition.phase = 'in';
            this._transition.elapsed = 0;
            await sleep(this._transition.duration * 500);
            this._transition = null;
        }
        this._loading = false;
        this.events.emit('scene:loaded', id);
    }
    /** Reload current scene. */
    async reloadScene(world) {
        if (this._currentId) {
            await this.loadScene(this._currentId, world);
        }
    }
    /* ── Transition update ──────────────────────────────────────── */
    updateTransition(dt) {
        if (this._transition) {
            this._transition.elapsed += dt;
        }
    }
    /* ── Prefabs ────────────────────────────────────────────────── */
    registerPrefab(name, prefab) {
        this.prefabs.set(name, prefab);
    }
    /** Instantiate a prefab into the world. Returns the root entity ID. */
    instantiate(world, prefabName, overrides) {
        const prefab = this.prefabs.get(prefabName);
        if (!prefab)
            throw new Error(`Prefab "${prefabName}" not registered.`);
        return this.instantiatePrefab(world, prefab, overrides);
    }
    instantiatePrefab(world, prefab, overrides) {
        var _a;
        const entity = world.createEntity((_a = overrides === null || overrides === void 0 ? void 0 : overrides.name) !== null && _a !== void 0 ? _a : prefab.name);
        for (const tag of prefab.tags)
            entity.tags.add(tag);
        for (const compDef of prefab.components) {
            const comp = world.addComponent(entity.id, compDef.type);
            if (compDef.overrides)
                Object.assign(comp, compDef.overrides);
        }
        // Apply position override
        if (overrides === null || overrides === void 0 ? void 0 : overrides.position) {
            const t = world.getComponent(entity.id, 'Transform');
            if (t) {
                t.position = { ...overrides.position };
                t.prevPosition = { ...overrides.position };
            }
        }
        // Children
        if (prefab.children) {
            for (const child of prefab.children) {
                const childId = this.instantiatePrefab(world, child);
                world.setParent(childId, entity.id);
            }
        }
        return entity.id;
    }
    /* ── Serialization ──────────────────────────────────────────── */
    serializeScene(world, id, name) {
        const entities = [];
        for (const entity of world.allEntities()) {
            const components = [];
            // Serialize all known component types on this entity
            const knownTypes = [
                'Transform', 'Sprite', 'Shape', 'Collider2D', 'RigidBody2D',
                'Text', 'Animator', 'Script', 'AudioSource', 'ParticleEmitter', 'CameraTarget',
            ];
            for (const type of knownTypes) {
                const comp = world.getComponent(entity.id, type);
                if (comp) {
                    const data = { ...comp };
                    delete data.type;
                    delete data.entityId;
                    components.push({ type: type, data });
                }
            }
            entities.push({
                id: entity.id,
                name: entity.name,
                tags: Array.from(entity.tags),
                components,
                children: entity.children,
            });
        }
        return { id, name, entities, settings: {} };
    }
    /** Deserialize a scene into a world. */
    deserializeScene(world, data) {
        world.clear();
        for (const se of data.entities) {
            const entity = world.createEntity(se.name);
            for (const tag of se.tags)
                entity.tags.add(tag);
            for (const sc of se.components) {
                const type = sc.type;
                world.addComponent(entity.id, type, sc.data);
            }
        }
        // Restore parent/child relationships
        for (const se of data.entities) {
            for (const childId of se.children) {
                world.setParent(childId, se.id);
            }
        }
    }
}
/* ── Utility ──────────────────────────────────────────────────── */
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

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