import { extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
import { getComponentSvc } from "@ibgib/web-gib/dist/ui/component/ibgib-component-service.mjs";
import { IbGibDynamicComponentMeta } from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";

import { APP_CONFIG } from "../../constants.mjs";
import { getIbGibGlobalThis_{{APP_CLASSNAME_PREFIX}} } from "../../helpers.web.mjs";
import {
    ID_SHELL_CONTAINER,
    EVENT_SHELL_READY,
} from "./{{APP_DIR_NAME}}-shell-constants.mjs";

/**
 * Singleton service for managing the {{APP_HUMAN_NAME}} UI shell.
 * Coordinates component registration and high-level DOM interactions.
 */
export class {{APP_CLASSNAME_PREFIX}}ShellService {
    private lc: string = `[{{APP_CLASSNAME_PREFIX}}ShellService]`;

    // Elements
    private shellContainer: HTMLElement | null = null;

    /**
     * Promise that resolves when the shell service has completed its
     * asynchronous initialization (e.g. component registration).
     */
    public initialized: Promise<void>;

    constructor() {
        this.initialized = this.initialize();
    }

    /**
     * Orchestrates the synchronous and asynchronous initialization of the shell.
     */
    private async initialize(): Promise<void> {
        this.initElements();
        this.initEventHandlers();
        await this.registerComponents();
    }

    /**
     * Registers application-specific components with the global component service.
     */
    private async registerComponents(): Promise<void> {
        const lc = `${this.lc}[${this.registerComponents.name}]`;
        try {
            const componentsMeta: IbGibDynamicComponentMeta[] = [
                // Add your individual component metas or sets here, e.g.:
                // new MyAwesomeComponentMeta(),
                // ...MyAwesomeComponentsSet,
            ];
            const componentSvc = await getComponentSvc();
            for (let componentMeta of componentsMeta) {
                componentSvc.registerComponentMeta(componentMeta);
            }
        } catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
    }

    private initElements(): void {
        const lc = `${this.lc}[${this.initElements.name}]`;
        try {
            // Placeholder: this.shellContainer = document.getElementById(ID_SHELL_CONTAINER);
        } catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
        }
    }

    private initEventHandlers(): void {
        const lc = `${this.lc}[${this.initEventHandlers.name}]`;
        try {
            // Register global or shell-level event listeners here.
        } catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
        }
    }

    /**
     * Called by `bootstrap.mts` when the ibGib engine and metaspace are ready.
     * Use this to reveal or activate interactive UI elements.
     */
    public async onEngineReady(): Promise<void> {
        const lc = `${this.lc}[${this.onEngineReady.name}]`;
        try {
            await this.initialized;
            console.log(`${lc} {{APP_HUMAN_NAME}} Shell Service is ready.`);

            // 1. Get the app context from global state
            const ibGibGlobalThis = getIbGibGlobalThis_{{APP_CLASSNAME_PREFIX}}(APP_CONFIG);
            const appIbGib = ibGibGlobalThis.initialCommentIbGib;
            if (!appIbGib) {
                throw new Error(`initialCommentIbGib not found on globalThis.`);
            }

            // 2. Get the main component instance
            const componentSvc = await getComponentSvc();
            const component = await componentSvc.getComponentInstance({
                path: '{{APP_DIR_NAME}}-main',
                ibGibAddr: getIbGibAddr({ ibGib: appIbGib }),
                useRegExpPrefilter: true,
            });

            if (!component) {
                throw new Error(`Failed to get component instance for app.`);
            }

            // 3. Inject into the DOM
            const appRoot = document.getElementById(ID_APP_ROOT);
            if (appRoot) {
                appRoot.innerHTML = ''; // Clear loading message
                appRoot.appendChild(component as any);
            } else {
                console.warn(`${lc} #${ID_APP_ROOT} not found in DOM.`);
            }

            window.dispatchEvent(new CustomEvent(EVENT_SHELL_READY));
        } catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
        }
    }
}

/**
 * Returns the singleton instance of the Shell Service, initializing it on
 * globalThis if necessary.
 */
export function get{{APP_CLASSNAME_PREFIX}}ShellSvc(): {{APP_CLASSNAME_PREFIX}}ShellService {
    const lc = `[get{{APP_CLASSNAME_PREFIX}}ShellSvc]`;
    const ibGibGlobalThis = getIbGibGlobalThis_{{APP_CLASSNAME_PREFIX}}(APP_CONFIG);
    if (!ibGibGlobalThis.{{APP_VAR_NAME}}ShellSvc) {
        if (typeof (console) !== 'undefined') {
            console.log(`${lc} initializing {{APP_CLASSNAME_PREFIX}}ShellService singleton on globalThis... (I: genuuid)`);
        }
        ibGibGlobalThis.{{APP_VAR_NAME}}ShellSvc = new {{APP_CLASSNAME_PREFIX}}ShellService();
    }
    return ibGibGlobalThis.{{APP_VAR_NAME}}ShellSvc;
}
