import { AppObjectUC, getSingletonComponent, } from "@vived/core";
import { GetAssetBlobURLUC, GetLinkedAssetsUC, ShowSpinnerUC, } from "../../Dispatcher";
import { GlbModelRepo, LoadGlbFileUC } from "../../GLBModel";
import { ChannelModelRepo, ChannelModelState, } from "../Entities";
import { ChannelModelViewFactory } from "./ChannelModelViewFactory";
export const SCENE_MODEL_DATA_ASSET_LINK_TYPE = "default_model_data";
export class LoadChannelModelUC extends AppObjectUC {
    static get(appObjects) {
        return getSingletonComponent(LoadChannelModelUC.type, appObjects);
    }
}
LoadChannelModelUC.type = "LoadChannelModelUC";
export function makeLoadChannelModelUC(appObject) {
    return new LoadChannelModelUCImp(appObject);
}
class LoadChannelModelUCImp extends LoadChannelModelUC {
    get channelModelRepo() {
        return this.getCachedSingleton(ChannelModelRepo.type);
    }
    get loadGlbFile() {
        return this.getCachedSingleton(LoadGlbFileUC.type);
    }
    get glbRepo() {
        return this.getCachedSingleton(GlbModelRepo.type);
    }
    get channelModelViewFactory() {
        return this.getCachedSingleton(ChannelModelViewFactory.type);
    }
    get getAssetBlob() {
        return this.getCachedSingleton(GetAssetBlobURLUC.type)
            ?.doDispatch;
    }
    get getLinkedAsset() {
        return this.getCachedSingleton(GetLinkedAssetsUC.type)
            ?.doDispatch;
    }
    get showSpinner() {
        return this.getCachedSingleton(ShowSpinnerUC.type)
            ?.showSpinner;
    }
    waitForExistingToLoad(existing) {
        return new Promise((resolve, reject) => {
            const onExistingModelChange = () => {
                if (existing.state === ChannelModelState.READY) {
                    existing.removeChangeObserver(onExistingModelChange);
                    resolve(existing);
                }
                else if (existing.state === ChannelModelState.ERROR) {
                    existing.removeChangeObserver(onExistingModelChange);
                    reject(existing.modelError);
                }
            };
            existing.addChangeObserver(onExistingModelChange);
        });
    }
    constructor(appObject) {
        super(appObject, LoadChannelModelUC.type);
        this.loadChannelModel = (modelID) => {
            if (!this.channelModelRepo ||
                !this.glbRepo ||
                !this.loadGlbFile ||
                !this.getAssetBlob ||
                !this.getLinkedAsset ||
                !this.channelModelViewFactory ||
                !this.showSpinner) {
                this.error("Missing Component(s)");
                return Promise.reject(new Error("Missing Component(s)"));
            }
            const existingChannelModel = this.channelModelRepo.getForAppObject(modelID);
            if (existingChannelModel) {
                if (existingChannelModel.state === ChannelModelState.READY) {
                    return Promise.resolve(existingChannelModel);
                }
                else if (existingChannelModel.state === ChannelModelState.LOADING) {
                    return this.waitForExistingToLoad(existingChannelModel);
                }
                else if (existingChannelModel.state === ChannelModelState.ERROR) {
                    return Promise.reject(existingChannelModel.modelError);
                }
            }
            const channelModel = this.channelModelRepo.createChannelModel(modelID);
            channelModel.state = ChannelModelState.LOADING;
            const getLinkedAsset = this.getLinkedAsset;
            const getAssetBlob = this.getAssetBlob;
            const channelModelViewFactory = this.channelModelViewFactory;
            let closeSpinner = () => { };
            return this.showSpinner("Loading Model", "Loading channel model...")
                .then((closeCB) => {
                closeSpinner = closeCB;
                return getAssetBlob(modelID);
            })
                .then((blobURL) => {
                const glbModel = this.glbRepo.createGlbModel(modelID);
                return this.loadGlbFile.loadBlobURL(blobURL, glbModel);
            })
                .then(() => {
                return getLinkedAsset(modelID, SCENE_MODEL_DATA_ASSET_LINK_TYPE);
            })
                .then((dataAssets) => {
                if (dataAssets.length === 0) {
                    return Promise.reject(new Error("Model asset does not have data"));
                }
                return getAssetBlob(dataAssets[0].id);
            })
                .then((blobURL) => {
                return this.blobToJSON(blobURL);
            })
                .then((dto) => {
                channelModel.setupFromData(dto);
                channelModelViewFactory.initializeView(channelModel);
                channelModel.state = ChannelModelState.READY;
                closeSpinner();
                return channelModel;
            })
                .catch((e) => {
                closeSpinner();
                return Promise.reject(e);
            });
        };
        this.blobToJSON = (url) => {
            return fetch(url).then((resp) => {
                return resp.json();
            });
        };
        this.appObjects.registerSingleton(this);
    }
}
//# sourceMappingURL=LoadChannelModelUC.js.map