import { h, Env } from "@stencil/core";
import { generateUUID, getKBContent, getWidgetContentByType } from "../../utils/utils";
import { processChatData as processChatDataHelper } from "../../utils/botHelpers/processCarouselData";
import { renderTemplateData as renderTemplateDataHelper, processTemplateData as processTemplateDataHelper, initializeScript as initializeScriptHelper, } from "../../utils/botHelpers/botHelpers";
import { Handlebars } from "../../utils/helpers";
import { ai12zManager } from "../../utils/ai12z-manager";
import DOMPurify from "dompurify";
import showDown from "showdown";
export class Ai12zContainer {
    constructor() {
        this.isDisconnected = false;
        this.dataKey = Env.DATA_KEY || "";
        this.dataMode = Env.DATA_MODE || "prod";
        this.keyName = "";
        this.instanceId = "";
        this.renderType = "integration";
        this.contentTemplate = "";
        this.isLoading = false;
        this.error = "";
        this.contentText = "";
        this.htmlWidgetMarkup = "";
        this.domId = `widget-${generateUUID()}`;
        this.registrationKey = "";
        this.requestVersion = 0;
        this.lastKbResponse = null;
        this.markAsActive = () => {
            if (this.registrationKey) {
                ai12zManager.setActive(this.registrationKey);
            }
        };
        this.initializeScript = id => {
            // Re-assert activeness right before the script runs
            this.markAsActive();
            return initializeScriptHelper(id, this.mainObject);
        };
    }
    get mainObject() {
        if (!window["ai12z"]) {
            window["ai12z"] = {};
        }
        return window["ai12z"];
    }
    getResolvedKeyName() {
        var _a, _b, _c, _d, _e;
        const propKeyName = (_a = this.keyName) === null || _a === void 0 ? void 0 : _a.trim();
        const attrKeyName = ((_c = (_b = this.el) === null || _b === void 0 ? void 0 : _b.getAttribute("key-name")) === null || _c === void 0 ? void 0 : _c.trim()) || "";
        if (propKeyName) {
            return propKeyName;
        }
        if (attrKeyName) {
            return attrKeyName;
        }
        if (typeof window === "undefined") {
            return "";
        }
        const urlParams = new URLSearchParams(window.location.search);
        return ((_d = urlParams.get("keyName")) === null || _d === void 0 ? void 0 : _d.trim()) || ((_e = urlParams.get("keyname")) === null || _e === void 0 ? void 0 : _e.trim()) || "";
    }
    waitForNextPaint(delayMs = 0) {
        return new Promise(resolve => {
            requestAnimationFrame(() => {
                if (delayMs > 0) {
                    setTimeout(() => resolve(), delayMs);
                    return;
                }
                resolve();
            });
        });
    }
    async renderControl(widgetResponse) {
        await this.waitForNextPaint(Ai12zContainer.CONTAINER_MOUNT_DELAY_MS);
        switch (this.renderType) {
            case "carousel":
                await processChatDataHelper({
                    id: `carousel-${this.domId}`,
                }, { controlData: widgetResponse }, this.el, (chatData) => this.hideSpinner(chatData), _chatData => {
                    // this.survey.emit({ results: chatData, type: "update" })
                }, widgetResponse.scripts, widgetResponse.styles, false, "widget");
                break;
            case "template":
                let resolved = false;
                // We must wrap this in a promise if processTemplateDataHelper
                // doesn't natively return one that waits for the internal callback
                await new Promise(resolve => {
                    const safeResolve = () => {
                        if (!resolved) {
                            resolved = true;
                            resolve();
                        }
                    };
                    processTemplateDataHelper({ id: `html-${this.domId}` }, { controlData: widgetResponse, controlType: widgetResponse.controlType }, this.el.shadowRoot, (chatData) => this.hideSpinner(chatData), async (chatData) => {
                        await this.renderTemplateData(chatData);
                        safeResolve(); // Only resolve once the template AND scripts are done
                    }, _chatData => {
                        this.markAsActive();
                    }, Handlebars).then(safeResolve);
                });
                break;
            case "content": {
                this.lastKbResponse = widgetResponse;
                const resData = widgetResponse === null || widgetResponse === void 0 ? void 0 : widgetResponse.data;
                if (!resData) {
                    this.error = "Knowledge base content unavailable.";
                    this.errored.emit(this.error);
                    break;
                }
                let { question = "", answer = "" } = resData;
                answer = new showDown.Converter().makeHtml(answer);
                question = new showDown.Converter().makeHtml(question);
                // const question = resData.question || ""
                // const answer = resData.answer || ""
                if (this.contentTemplate) {
                    const compiled = Handlebars.compile(this.contentTemplate);
                    this.contentText = compiled({ question, answer });
                    // console.log("Compiled content with template:", this.contentText)
                    this.contentText = DOMPurify.sanitize(this.contentText);
                }
                else {
                    this.contentText = DOMPurify.sanitize(answer);
                }
                break;
            }
        }
    }
    async componentWillLoad() {
        var _a;
        // Register immediately so getInstance() works as soon as the component
        // starts mounting — before the async API call completes.
        this.registrationKey = ((_a = this.instanceId) === null || _a === void 0 ? void 0 : _a.trim()) || `container-${this.domId}`;
        ai12zManager.register(this.registrationKey, this);
        if ((this.getResolvedKeyName() && this.parameters !== undefined) || this.renderType === "content") {
            await this.invokeApi();
        }
    }
    componentDidLoad() {
        if (typeof window !== "undefined" && !window.Handlebars) {
            ;
            window.Handlebars = Handlebars;
        }
        this.el.addEventListener("focusin", this.markAsActive);
        this.el.addEventListener("pointerenter", this.markAsActive);
    }
    disconnectedCallback() {
        this.el.removeEventListener("focusin", this.markAsActive);
        this.el.removeEventListener("pointerenter", this.markAsActive);
        this.isDisconnected = true;
        if (this.registrationKey) {
            ai12zManager.unregister(this.registrationKey);
        }
    }
    async onParametersChanged(newValue, oldValue) {
        if (newValue === oldValue)
            return;
        if (!this.getResolvedKeyName())
            return;
        await this.invokeApi(newValue);
    }
    onContentTemplateChanged() {
        if (this.renderType !== "content" || !this.lastKbResponse)
            return;
        const { question = "", answer = "" } = this.lastKbResponse.data || {};
        const rendered = this.contentTemplate ? Handlebars.compile(this.contentTemplate)({ question, answer }) : answer;
        this.contentText = DOMPurify.sanitize(rendered);
    }
    async invokeApi(parametersSnapshot = this.parameters) {
        this.error = "";
        const currentRequestVersion = ++this.requestVersion;
        const resolvedKeyName = this.getResolvedKeyName();
        if (!resolvedKeyName) {
            this.error = 'Key Name is required. Provide the "key-name" attribute or pass "keyName" in the URL.';
            this.errored.emit(this.error);
            this.isLoading = false;
            return;
        }
        // ENQUEUE THE ENTIRE PROCESS
        // We chain the new task to the tail of the existing promise chain
        Ai12zContainer.renderQueueTail = Ai12zContainer.renderQueueTail
            .then(async () => {
            try {
                if (this.isDisconnected || currentRequestVersion !== this.requestVersion) {
                    return;
                }
                if (this.registrationKey) {
                    ai12zManager.setActive(this.registrationKey);
                }
                this.isLoading = true;
                let widgetResponse;
                if (this.renderType === "content") {
                    widgetResponse = await getKBContent(this.dataKey, this.dataMode, resolvedKeyName);
                }
                else {
                    widgetResponse = await getWidgetContentByType(this.dataKey, this.dataMode, resolvedKeyName, parametersSnapshot);
                    this.renderType = widgetResponse.controlType;
                }
                // widgetResponse = await getWidgetContentByType(this.dataKey, this.dataMode, resolvedKeyName, parametersSnapshot)
                if (this.isDisconnected || currentRequestVersion !== this.requestVersion) {
                    return;
                }
                // Render the target host container first; renderControl queries it from shadow DOM.
                this.isLoading = false;
                await this.waitForNextPaint(150);
                // Execute Rendering
                await this.renderControl(widgetResponse);
                if (this.isDisconnected || currentRequestVersion !== this.requestVersion) {
                    return;
                }
                this.responseReceived.emit(widgetResponse);
                // CRITICAL: Wait for the browser to actually finish painting
                // and scripts to settle before letting the next component start.
                await this.waitForNextPaint(600);
            }
            catch (error) {
                this.error = (error === null || error === void 0 ? void 0 : error.message) || "Failed to load widget response";
                console.error("Failed to retrieve data", error);
                // Raised an event "errored" for developer to render the message or not
                this.errored.emit(this.error);
            }
            finally {
                this.isLoading = false;
            }
        })
            .catch(err => {
            console.error("Queue item failed — chain preserved:", err);
        });
    }
    async renderTemplateData(chatData) {
        await renderTemplateDataHelper(chatData, this.el, [], this.mainObject, this.initializeScript);
    }
    hideSpinner(chatData) {
        // Logic for hiding the spinner (assumed to return a Promise if async is needed)
        return new Promise(resolve => {
            const renderedBubble = this.el.shadowRoot.querySelector(`#${chatData.id}`);
            if (renderedBubble) {
                const spinner = renderedBubble.querySelector("#spinner");
                if (spinner) {
                    spinner.style.display = "none";
                }
            }
            resolve(true);
        });
    }
    renderSpinner() {
        return (h("div", { class: "widget-spinner", id: "spinner" }, h("div", { class: "widget-spinner-pulse" }, h("div", { class: "widget-spinner-body" }, h("div", { class: "widget-spinner-bar" }), h("div", { class: "widget-spinner-rows" }, h("div", { class: "widget-spinner-grid" }, h("div", { class: "widget-spinner-col-wide" }), h("div", { class: "widget-spinner-col-narrow" })), h("div", { class: "widget-spinner-bar" }))))));
    }
    renderByType() {
        switch (this.renderType) {
            case "carousel":
                return (h("div", { class: "carousel-grid", id: `carousel-${this.domId}` }, this.renderSpinner()));
            case "template":
                return (h("div", { class: "html-widget", id: `html-${this.domId}` }, this.renderSpinner()));
            default:
                return h("div", { class: "content-widget", id: `content-${this.domId}`, innerHTML: this.contentText });
        }
    }
    render() {
        return (h("div", { key: 'ec7c4261c505fb29882acf30d0c9c10a8703dc51', class: "ai12z-container-root" }, this.isLoading && h("div", { key: 'ab3899fe20a637293b1fa5c24b40edf9cc20f333', class: "state-message" }, "Loading..."), !this.isLoading && this.error && h("div", { key: 'd70e83ff89ab6df1b090e7034f021c71466796c6', class: "state-message error" }, this.error), !this.isLoading && !this.error && this.renderByType()));
    }
    static get is() { return "ai12z-container"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["./ai12z-container.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["ai12z-container.css"]
        };
    }
    static get properties() {
        return {
            "dataKey": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "data-key",
                "defaultValue": "Env.DATA_KEY || \"\""
            },
            "dataMode": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "data-mode",
                "defaultValue": "Env.DATA_MODE || \"prod\""
            },
            "keyName": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "key-name",
                "defaultValue": "\"\""
            },
            "instanceId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "instance-id",
                "defaultValue": "\"\""
            },
            "parameters": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "parameters"
            },
            "renderType": {
                "type": "string",
                "mutable": true,
                "complexType": {
                    "original": "RenderType",
                    "resolved": "\"carousel\" | \"content\" | \"integration\" | \"template\"",
                    "references": {
                        "RenderType": {
                            "location": "global",
                            "id": "global::RenderType"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "render-type",
                "defaultValue": "\"integration\""
            },
            "contentTemplate": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "content-template",
                "defaultValue": "\"\""
            }
        };
    }
    static get states() {
        return {
            "isLoading": {},
            "error": {},
            "contentText": {},
            "htmlWidgetMarkup": {},
            "domId": {}
        };
    }
    static get events() {
        return [{
                "method": "responseReceived",
                "name": "responseReceived",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "errored",
                "name": "errored",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                }
            }];
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "parameters",
                "methodName": "onParametersChanged"
            }, {
                "propName": "contentTemplate",
                "methodName": "onContentTemplateChanged"
            }];
    }
}
Ai12zContainer.renderQueueTail = Promise.resolve();
/** Minimum delay for shadow DOM to mount the render-type container. */
Ai12zContainer.CONTAINER_MOUNT_DELAY_MS = 150;
