import { createApp, type App as VueApp } from 'vue'

import App from '../App.vue'
import '../assets/main.css'
import { createPinia, disposePinia } from 'pinia';
import { ConfigureLibOutput, type LibOutputConfig } from './libOutputConfig';
import { useEvent } from '../stores/eventStore';
import { useScene, useSceneRaw } from '../stores/sceneStore';
import { CADFactory, LayerNode, PhysicalMaterialRecord, TextureTableRecord } from 'webcad_ue4_api';
import { ToDeflatedBase64 } from '../helpers/helper.material';

let app: VueApp<Element> = undefined;

/**
 * 挂载材质编辑器到指定元素
*  @param element 要挂载的HTML元素
 * @param options 程序配置
 */
export function Mount(element: string | Element, options?: Partial<LibOutputConfig>) {
    options && ConfigureLibOutput(options);

    const pinia = createPinia();

    // TODO: Warn: 有BUG，部分实体的构造函数名带_1后缀，原因未知，这会导致CADFactory在创建实体时找不到注册的类名
    // @ts-ignore
    console.log(CADFactory['factory'].objectNameMap); // 为什么Map中的构造函数名带_1后缀？
    CADFactory.RegisterObjectAlias(LayerNode, "LayerNode");
    CADFactory.RegisterObjectAlias(TextureTableRecord, "TextureTableRecord");
    CADFactory.RegisterObjectAlias(PhysicalMaterialRecord, "PhysicalMaterialRecord");

    app = createApp(App);
    app.use(pinia)
        .mount(element);
}

/** 对程序配置进行更改 */
export function Configure(options: Partial<LibOutputConfig>) {
    ConfigureLibOutput(options);
    useEvent().Publish('update-config');
}

/** 卸载已经挂载的DOM */
export function Unmount() {
    app.unmount();
}

/** 手动进行材质提交 */
export function Submit() {
    useEvent().Publish('submit');
}

/** 更新材质贴图 */
export function UpdateTexture() {
    useEvent().Publish('update-texture');
}

export async function SubmitRawAsync(options: { textureSrc: string }): Promise<{ file: string }> {
    let pinia = createPinia();
    const scene = useSceneRaw(pinia);

    const virtualDom = document.createElement('div');
    virtualDom.style.display = 'none';
    scene.Initial(virtualDom);
    await scene.ChangeTextureFromUrlAsync(options.textureSrc);
    var json = ToDeflatedBase64(await scene.SerializeMaterialAsync());

    scene.Dispose();
    virtualDom.remove();
    disposePinia(pinia);
    return {
        file: json
    };
}