import { SceneSystem, ActorCollection, ActorCreator, TemplateCollection, } from 'dacha';
import { EventType } from '../../../events';
import { includesArray } from '../../../utils/includes-array';
import { getSavedSelectedSceneId } from '../../../utils/get-saved-selected-scene-id';
import { ALLOWED_COMPONENTS } from './consts';
import { omit, removeAllChildren } from './utils';
import { watchTemplates, watchActors, } from './watchers';
export class SceneViewer extends SceneSystem {
    constructor(options) {
        super();
        this.handleSelectScene = (event) => {
            if (this.currentScene === event.sceneId) {
                return;
            }
            removeAllChildren(this.editorScene, this.mainActorId);
            this.loadScene(event.sceneId);
        };
        const { world, scene, actorSpawner, mainActorId, } = options;
        this.world = world;
        this.editorScene = scene;
        this.actorSpawner = actorSpawner;
        this.actorCollection = new ActorCollection(scene);
        this.mainActorId = mainActorId;
        this.configStore = world.data.configStore;
        this.editorConfig = world.data.editorConfig;
        const mainActor = scene.findChildById(mainActorId);
        if (!mainActor) {
            throw new Error('Can\'t find the main actor');
        }
        this.world.data.mainActor = mainActor;
        const templateCollection = new TemplateCollection();
        const templates = this.configStore.get(['templates']);
        templates.forEach((template) => {
            templateCollection.register(omit(template));
        });
        this.templateCollection = templateCollection;
        this.actorCreator = new ActorCreator(ALLOWED_COMPONENTS, templateCollection);
        this.world.data.actorCreator = this.actorCreator;
        const selectedSceneId = getSavedSelectedSceneId(this.configStore);
        if (selectedSceneId) {
            this.loadScene(selectedSceneId);
        }
        this.world.addEventListener(EventType.SelectScene, this.handleSelectScene);
        this.watchStore();
    }
    onSceneDestroy() {
        var _a;
        this.world.removeEventListener(EventType.SelectScene, this.handleSelectScene);
        (_a = this.subscription) === null || _a === void 0 ? void 0 : _a.call(this);
    }
    watchStore() {
        const listener = (path) => {
            const scenePath = this.currentScene && ['scenes', `id:${this.currentScene}`];
            const scene = scenePath ? this.configStore.get(scenePath) : undefined;
            const options = {
                path,
                store: this.configStore,
                editorScene: this.editorScene,
                actorCollection: this.actorCollection,
                actorCreator: this.actorCreator,
                templateCollection: this.templateCollection,
                scene,
                prevScene: this.prevScene,
            };
            if (includesArray(path, ['templates'])) {
                watchTemplates(options);
            }
            if (this.currentScene && includesArray(path, ['scenes'])) {
                watchActors(options);
            }
            this.prevScene = scene;
        };
        this.subscription = this.configStore.subscribe(listener);
    }
    loadScene(sceneId) {
        const scenes = this.configStore.get(['scenes']);
        const selectedScene = scenes.find((scene) => scene.id === sceneId);
        if (selectedScene) {
            selectedScene.actors.forEach((actorConfig) => {
                this.editorScene.appendChild(this.actorCreator.create(omit(actorConfig)));
            });
        }
        this.prevScene = selectedScene;
        this.currentScene = sceneId;
    }
}
SceneViewer.systemName = 'SceneViewer';
