'use strict';

function waitForElementRender(element, timeout = 2000) {
    return new Promise((resolve, _reject) => {
        const checkReady = () => {
            if (element && element.childNodes.length > 0) {
                resolve();
                return true;
            }
            return false;
        };
        if (checkReady())
            return;
        const observer = new MutationObserver(() => {
            if (checkReady()) {
                observer.disconnect();
            }
        });
        observer.observe(element, {
            childList: true,
            subtree: true,
        });
        setTimeout(() => {
            observer.disconnect();
            resolve();
        }, timeout);
    });
}
// function insertCustomAssets(targetContainer: Element, customCss?: string, customJs?: string): void {
//   if (customCss) {
//     const existingLink = targetContainer.querySelector(`link[rel="stylesheet"][href="${customCss}"]`)
//     if (!existingLink) {
//       const linkEl = document.createElement("link")
//       linkEl.setAttribute("rel", "stylesheet")
//       linkEl.setAttribute("href", customCss)
//       targetContainer.appendChild(linkEl)
//     }
//   }
//   if (customJs) {
//     const existingScript = targetContainer.querySelector(`script[src="${customJs}"]`)
//     if (!existingScript) {
//       const scriptEl = document.createElement("script")
//       scriptEl.setAttribute("type", "text/javascript")
//       scriptEl.setAttribute("src", customJs)
//       targetContainer.appendChild(scriptEl)
//     }
//   }
// }
// ✅ Move renderTemplateData to helper with proper typing
async function renderTemplateData(chatData, element, scriptArray, mainObject, initializeScriptCallback, inputType) {
    var _a, _b, _c, _d, _e, _f, _g;
    try {
        if (!mainObject[`${chatData.id}`]) {
            mainObject[`${chatData.id}`] = {};
        }
        let domId = chatData.id;
        if (inputType === "kb") {
            domId = chatData.controlDomId;
        }
        const scripts = Array.from((_b = (_a = element.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`#${domId} script`)) !== null && _b !== void 0 ? _b : []);
        for (const script of scripts) {
            const newScript = document.createElement("script");
            newScript.type = "text/javascript";
            if (script.src) {
                newScript.src = script.src;
                scriptArray.push(newScript);
            }
            else {
                newScript.innerHTML = script.innerHTML;
                scriptArray.push(newScript);
            }
            (_c = script.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(script);
            if (newScript.src && !((_d = element.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector(`script[src="${newScript.src}"]`))) {
                await new Promise((resolve, reject) => {
                    var _a;
                    newScript.onload = () => resolve();
                    newScript.onerror = () => reject(new Error(`Failed to load script: ${newScript.src}`));
                    (_a = element.shadowRoot) === null || _a === void 0 ? void 0 : _a.appendChild(newScript);
                });
            }
            else if (!newScript.src) {
                const existing = Array.from((_f = (_e = element.shadowRoot) === null || _e === void 0 ? void 0 : _e.querySelectorAll("script[type='text/javascript']")) !== null && _f !== void 0 ? _f : element.querySelectorAll("script[type='text/javascript']")).some(s => { var _a, _b; return ((_a = s.innerHTML) === null || _a === void 0 ? void 0 : _a.trim()) === ((_b = newScript.innerHTML) === null || _b === void 0 ? void 0 : _b.trim()); });
                if (!existing) {
                    (_g = element.shadowRoot) === null || _g === void 0 ? void 0 : _g.appendChild(newScript);
                    // Yield to the microtask queue so inline scripts execute before continuing
                    await new Promise(resolve => queueMicrotask(resolve));
                }
            }
        }
        // All scripts processed — now initialize and await if the callback is async
        await initializeScriptCallback(chatData.id);
    }
    catch (error) {
        console.error("Error in renderTemplateData:", error);
    }
}
// Helper to load CSS and wait for it
function loadStyle(url, root) {
    return new Promise((resolve, reject) => {
        const existingLink = root.querySelector(`link[rel="stylesheet"][href="${url}"]`);
        if (existingLink) {
            if (existingLink.sheet) {
                resolve();
                return;
            }
            existingLink.addEventListener("load", () => resolve(), { once: true });
            existingLink.addEventListener("error", () => reject(new Error(`Failed to load style: ${url}`)), { once: true });
            return;
        }
        const link = document.createElement("link");
        link.rel = "stylesheet";
        link.href = url;
        link.onload = () => resolve();
        link.onerror = () => reject(new Error(`Failed to load style: ${url}`));
        root.appendChild(link);
    });
}
// Helper to load JS (if needed)
function loadScript(url, container) {
    return new Promise((resolve, reject) => {
        const script = document.createElement("script");
        script.src = url;
        script.onload = () => resolve();
        script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
        container.appendChild(script);
    });
}
// ✅ Add enhanced processTemplateData function
async function processTemplateData(chatData, data, shadowRoot, hideSpinnerCallback, renderTemplateCallback, updateMessagesCallback, Handlebars, inputType) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
    try {
        // Step 1: Hide the spinner
        await hideSpinnerCallback(chatData);
        let handletemplate;
        let currentResponse;
        const resolvedControlType = (_a = data.controlType) !== null && _a !== void 0 ? _a : (_b = data.controlData) === null || _b === void 0 ? void 0 : _b.controlType;
        if (resolvedControlType === "template") {
            const currentTemplate = (_c = data.controlData) === null || _c === void 0 ? void 0 : _c.template;
            currentResponse = (_e = (_d = data.controlData) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.source;
            const templateContent = (_f = currentTemplate === null || currentTemplate === void 0 ? void 0 : currentTemplate[0]) === null || _f === void 0 ? void 0 : _f.content;
            if (!templateContent) {
                console.error("processTemplateData: template content is missing", data);
                return;
            }
            handletemplate = Handlebars.compile(templateContent);
        }
        let targetContainer = shadowRoot.querySelector(`#${chatData.id}`);
        let styleContainer = inputType === "kb" ? (_g = shadowRoot.querySelector(`#${chatData.id}`)) === null || _g === void 0 ? void 0 : _g.shadowRoot : shadowRoot;
        // Step 2: Process template if container exists
        if (inputType === "kb") {
            targetContainer = shadowRoot.querySelector(`#${chatData.id}`).shadowRoot.querySelector(`#${chatData.controlDomId}`);
        }
        if (targetContainer) {
            // Register Handlebars helper
            Handlebars.registerHelper("processArray", function (array) {
                if (!Array.isArray(array)) {
                    return "";
                }
                return new Handlebars.SafeString(JSON.stringify(array));
            });
            // Set message ID if available
            if (data.controlData && data.controlData.data) {
                data.controlData.data.msgId = chatData.id;
                data.controlData.data.controlId = chatData.controlDomId;
            }
            const customCss = (_p = (_o = (_l = (_k = (_j = (_h = data.controlData) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.source) === null || _k === void 0 ? void 0 : _k.customCss) !== null && _l !== void 0 ? _l : (_m = data.controlData) === null || _m === void 0 ? void 0 : _m.styles) !== null && _o !== void 0 ? _o : data.styles) !== null && _p !== void 0 ? _p : "";
            const customJs = (_w = (_v = (_t = (_s = (_r = (_q = data.controlData) === null || _q === void 0 ? void 0 : _q.data) === null || _r === void 0 ? void 0 : _r.source) === null || _s === void 0 ? void 0 : _s.customJs) !== null && _t !== void 0 ? _t : (_u = data.controlData) === null || _u === void 0 ? void 0 : _u.scripts) !== null && _v !== void 0 ? _v : data.scripts) !== null && _w !== void 0 ? _w : "";
            // STEP 1: Wait for CSS to load FIRST
            if (customCss) {
                await loadStyle(customCss, styleContainer);
            }
            // Compile and set template content
            targetContainer.innerHTML = handletemplate({
                msgId: chatData.id,
                controlId: chatData.controlDomId,
                source: currentResponse,
                llm: data.controlData.data.llm,
                isBot: true,
            });
            // insertCustomAssets(targetContainer, customCss, customJs)
            targetContainer.classList.add("overflow-x-auto");
            targetContainer.classList.add("scroll-nobar");
            // Use double requestAnimationFrame for better timing
            requestAnimationFrame(() => {
                requestAnimationFrame(() => {
                    renderTemplateCallback(chatData);
                });
            });
            // STEP 3: Load JS (if necessary)
            if (customJs) {
                await loadScript(customJs, targetContainer);
            }
            // Wait for element to render
            await waitForElementRender(targetContainer);
            // Update chat data
            chatData.text = targetContainer.innerHTML;
            updateMessagesCallback(chatData);
        }
    }
    catch (error) {
        console.error("Error in processTemplateData:", error);
    }
}
// ✅ Add script initialization helper
async function initializeScript(id, mainObject) {
    const backoffDelays = [0, 50, 100, 200, 400, 800];
    for (const delay of backoffDelays) {
        if (delay > 0) {
            await new Promise(resolve => setTimeout(resolve, delay));
        }
        try {
            if (mainObject[`${id}`] && typeof mainObject[`${id}`]["onLoadCallback"] === "function") {
                mainObject[`${id}`]["onLoadCallback"]();
                return;
            }
        }
        catch (error) {
            console.error(`Error executing onLoadCallback for ${id}:`, error);
            return;
        }
    }
    console.warn(`onLoadCallback not available for ${id} after all retries`);
}
function getBotStateKey(projectId, configId) {
    const resolvedProjectId = projectId;
    return resolvedProjectId ? `ai12z-botState-${resolvedProjectId}-${configId}` : "ai12z-botState";
}
function getBotStateFromSession(projectId, configId) {
    const sessionKey = getBotStateKey(projectId, configId);
    const rawState = sessionStorage.getItem(sessionKey) || sessionStorage.getItem("ai12z-botState");
    if (!rawState) {
        return null;
    }
    try {
        const parsedState = JSON.parse(rawState);
        if (Array.isArray(parsedState)) {
            return parsedState.find(item => item.projectId === projectId) || null;
        }
        return parsedState;
    }
    catch (error) {
        console.error("AI12Z: Failed to parse bot state from sessionStorage:", error);
        return null;
    }
}
function checkBusinessHours(businessHours, timezone) {
    var _a, _b, _c;
    const nowUtc = new Date();
    // Get current date/time parts in the business timezone
    let parts;
    try {
        parts = new Intl.DateTimeFormat("en-US", {
            timeZone: timezone,
            weekday: "long",
            hour: "2-digit",
            minute: "2-digit",
            hour12: false,
        }).formatToParts(nowUtc);
    }
    catch (e) {
        console.error(`AI12Z: checkBusinessHours — invalid timezone "${timezone}"`, e);
        return false;
    }
    const currentDay = ((_a = parts.find(p => p.type === "weekday")) === null || _a === void 0 ? void 0 : _a.value) || "";
    const hour = ((_b = parts.find(p => p.type === "hour")) === null || _b === void 0 ? void 0 : _b.value) || "00";
    const minute = ((_c = parts.find(p => p.type === "minute")) === null || _c === void 0 ? void 0 : _c.value) || "00";
    const currentTime = `${hour}:${minute}`;
    // console.log(`Current day in ${timezone}:`, currentDay)
    // console.log(`Current time in ${timezone}:`, currentTime)
    // Find today's config
    const todayConfig = businessHours.find(item => item.day === currentDay);
    if (!todayConfig) {
        return false;
    }
    // Disabled
    if (!todayConfig.enabled) {
        return false;
    }
    // 24 hours open
    if (todayConfig.allDay) {
        return true;
    }
    // Convert all times into UTC minutes
    let currentUtcMinutes;
    let startUtcMinutes;
    let endUtcMinutes;
    try {
        currentUtcMinutes = getUtcMinutes(currentTime, timezone);
        startUtcMinutes = getUtcMinutes(todayConfig.startTime, timezone);
        endUtcMinutes = getUtcMinutes(todayConfig.endTime, timezone);
    }
    catch (e) {
        console.error("AI12Z: checkBusinessHours — cannot evaluate hours for day", todayConfig.day, e);
        return false;
    }
    // console.log({
    //   currentUtcMinutes,
    //   startUtcMinutes,
    //   endUtcMinutes,
    // })
    // Normal shift
    if (startUtcMinutes <= endUtcMinutes) {
        return currentUtcMinutes >= startUtcMinutes && currentUtcMinutes <= endUtcMinutes;
    }
    // Overnight shift
    return currentUtcMinutes >= startUtcMinutes || currentUtcMinutes <= endUtcMinutes;
}
function getUtcMinutes(time, timezone) {
    if (!/^\d{2}:\d{2}$/.test(time)) {
        throw new Error(`AI12Z: invalid time value "${time}" — expected HH:MM`);
    }
    const [hours, minutes] = time.split(":").map(Number);
    if (hours > 23 || minutes > 59) {
        throw new Error(`AI12Z: out-of-range time value "${time}" — hours must be 0–23 and minutes 0–59`);
    }
    const nowUtc = new Date();
    // Step 1: find today's calendar date in the target timezone
    const dateParts = new Intl.DateTimeFormat("en-CA", {
        timeZone: timezone,
        year: "numeric",
        month: "2-digit",
        day: "2-digit",
    }).formatToParts(nowUtc);
    const year = Number(dateParts.find(p => p.type === "year").value);
    const month = Number(dateParts.find(p => p.type === "month").value);
    const day = Number(dateParts.find(p => p.type === "day").value);
    // Step 2: build a candidate UTC timestamp using that date + desired wall-clock time
    const candidate = new Date(Date.UTC(year, month - 1, day, hours, minutes, 0));
    // Step 3: read back what the target timezone actually shows for the candidate,
    // then correct by the difference (one Newton step — exact for any real UTC offset)
    const tzParts = new Intl.DateTimeFormat("en-US", {
        timeZone: timezone,
        hour: "2-digit",
        minute: "2-digit",
        hourCycle: "h23",
    }).formatToParts(candidate);
    const tzH = Number(tzParts.find(p => p.type === "hour").value);
    const tzM = Number(tzParts.find(p => p.type === "minute").value);
    // Clamp error to ±840 min (widest real UTC offset is UTC±14h)
    let errorMin = (tzH - hours) * 60 + (tzM - minutes);
    if (errorMin > 840)
        errorMin -= 1440;
    if (errorMin < -840)
        errorMin += 1440;
    const utcDate = new Date(candidate.getTime() - errorMin * 60000);
    return utcDate.getUTCHours() * 60 + utcDate.getUTCMinutes();
}

exports.checkBusinessHours = checkBusinessHours;
exports.getBotStateFromSession = getBotStateFromSession;
exports.getBotStateKey = getBotStateKey;
exports.initializeScript = initializeScript;
exports.loadScript = loadScript;
exports.loadStyle = loadStyle;
exports.processTemplateData = processTemplateData;
exports.renderTemplateData = renderTemplateData;
