import thisCss from "./{{COMPONENT_NAME}}.css";
import thisHtml from "./{{COMPONENT_NAME}}.html";

import { extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";

import { getComponentCtorArg } from "../../helpers.web.mjs";
import {
    IbGibDynamicComponentMetaBase, IbGibDynamicComponentInstanceBase,
} from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
import {
    ElementsBase, IbGibDynamicComponentInstance,
    IbGibDynamicComponentInstanceInitOpts,
} from "@ibgib/web-gib/dist/ui/component/component-types.mjs";

export const {{COMPONENT_NAME_UPPER}}_COMPONENT_NAME = '{{COMPONENT_TAG_NAME}}';

/**
 * Metadata for the {{COMPONENT_CLASS_PREFIX}} component.
 * Handles custom element registration and instance creation.
 */
export class {{COMPONENT_CLASS_PREFIX}}ComponentMeta extends IbGibDynamicComponentMetaBase {
    protected lc: string = `[{{COMPONENT_CLASS_PREFIX}}ComponentMeta]`;

    routeRegExp?: RegExp = new RegExp(`^${ {{COMPONENT_NAME_UPPER}}_COMPONENT_NAME }$`);
    componentName = {{COMPONENT_NAME_UPPER}}_COMPONENT_NAME;

    constructor() {
        super(getComponentCtorArg());
        customElements.define(this.componentName, {{COMPONENT_CLASS_PREFIX}}ComponentInstance);
    }

    async createInstance({
        path,
        ibGibAddr
    }: {
        path: string;
        ibGibAddr: IbGibAddr;
    }): Promise<IbGibDynamicComponentInstance> {
        const lc = `${this.lc}[${this.createInstance.name}]`;
        const component = document.createElement(this.componentName) as {{COMPONENT_CLASS_PREFIX}}ComponentInstance;
        await component.initialize({
            ibGibAddr,
            meta: this,
            html: thisHtml,
            css: [thisCss],
        });
        return component;
    }
}

/**
 * References to DOM elements within the component's shadow root.
 */
interface {{COMPONENT_CLASS_PREFIX}}Elements extends ElementsBase {
    containerEl: HTMLDivElement;
    titleEl: HTMLHeadingElement;
}

/**
 * Concrete implementation of the {{COMPONENT_CLASS_PREFIX}} component.
 * Manages its own internal state and reacts to ibGib timeline updates.
 */
export class {{COMPONENT_CLASS_PREFIX}}ComponentInstance
    extends IbGibDynamicComponentInstanceBase<IbGib_V1, {{COMPONENT_CLASS_PREFIX}}Elements>
    implements IbGibDynamicComponentInstance<IbGib_V1, {{COMPONENT_CLASS_PREFIX}}Elements> {

    protected lc: string = `[{{COMPONENT_CLASS_PREFIX}}ComponentInstance]`;

    constructor() {
        super();
    }

    override async initialize(opts: IbGibDynamicComponentInstanceInitOpts): Promise<void> {
        await super.initialize(opts);
    }

    override async disconnected(): Promise<void> {
        // Called when the element is removed from the DOM.
    }

    /**
     * Called when the element is added to the DOM.
     * Use this to query elements and attach event listeners.
     */
    override async created(): Promise<void> {
        this.elements = {} as {{COMPONENT_CLASS_PREFIX}}Elements;
        if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: genuuid)`); }

        // Map shadow root elements
        // todo: complete this line. contentEl is required in ElementsBase
        // this.elements.contentEl =
        this.elements.containerEl = this.shadowRoot!.getElementById('container') as HTMLDivElement;
        this.elements.titleEl = this.shadowRoot!.getElementById('title') as HTMLHeadingElement;

        this.initHandlers();

        if (this.ibGibAddr && !this.ibGib) {
            await this.loadIbGib();
        }
        await this.renderUI();
    }

    private initHandlers() {
        if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: genuuid)`); }
        // Attach listeners here
    }

    /**
     * Updates the UI based on the current state of this.ibGib.
     */
    protected override async renderUI(): Promise<void> {
        const lc = `${this.lc}[${this.renderUI.name}]`;
        if (!this.ibGib || !this.elements) return;

        try {
            this.elements.titleEl.textContent = `IbGib Component: ${this.ibGib.ib}`;
        } catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
        }
    }

    /**
     * Automatically called by the framework when the ibGib timeline updates.
     */
    override async handleContextUpdated(): Promise<void> {
        const lc = `${this.lc}[${this.handleContextUpdated.name}]`;
        if (logalot) { console.log(`${lc} timeline updated.`); }
        await this.renderUI();
    }
}
