'use strict';

var index = require('./index-Ct2DwlDF.js');

let isAI12ZControlEnabled = null;
function getEndpoint(env) {
    env = env || index.Env.DATA_MODE;
    switch (env) {
        case "local-grpc":
            return `http://localhost:8080`;
        case "dev-grpc":
            return `https://socket.ai12z.net`;
        case "local":
            return `http://127.0.0.1:5000`;
        case "dev":
            return `https://dev-api.ai12z.net`;
        default:
            return `https://api.ai12z.net`;
    }
}
function getBackendProtocol(env) {
    env = env || index.Env.DATA_MODE;
    switch (env) {
        case "local-grpc":
            return "v2";
        default:
            return "legacy";
    }
}
function getPaprikaEndpoint(env) {
    env = env || index.Env.DATA_MODE;
    switch (env) {
        case "local":
            return `http://localhost:3000`;
        case "dev":
            return `https://dev.ai12z.net`;
        default:
            return `https://app.ai12z.net`;
    }
}
function getMetaInfo() {
    var _a, _b;
    const meta = {
        origin: (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.href, // Full URL of the current page
        title: document === null || document === void 0 ? void 0 : document.title,
        userAgent: navigator === null || navigator === void 0 ? void 0 : navigator.userAgent,
        referrer: document === null || document === void 0 ? void 0 : document.referrer,
        language: navigator === null || navigator === void 0 ? void 0 : navigator.language,
        legacyResponse: false,
        description: (_b = document.querySelector('meta[name="description"]')) === null || _b === void 0 ? void 0 : _b.getAttribute("content"),
    };
    return meta;
}
async function buildResponseError(response) {
    const fallbackMessage = `HTTP error! status: ${response.status}`;
    try {
        const contentType = response.headers.get("content-type") || "";
        if (contentType.includes("application/json")) {
            const errorPayload = await response.json();
            const message = (errorPayload === null || errorPayload === void 0 ? void 0 : errorPayload.message) ||
                (errorPayload === null || errorPayload === void 0 ? void 0 : errorPayload.error) ||
                (errorPayload === null || errorPayload === void 0 ? void 0 : errorPayload.details) ||
                (errorPayload === null || errorPayload === void 0 ? void 0 : errorPayload.title) ||
                fallbackMessage;
            return new Error(message);
        }
        const errorText = await response.text();
        return new Error(errorText || fallbackMessage);
    }
    catch (_error) {
        return new Error(fallbackMessage);
    }
}
async function apiFetch(url, payload) {
    var _a, _b;
    try {
        const requestPayload = Object.assign({}, payload);
        const meta = {
            origin: (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.href,
            title: document === null || document === void 0 ? void 0 : document.title,
            userAgent: navigator === null || navigator === void 0 ? void 0 : navigator.userAgent,
            referrer: document === null || document === void 0 ? void 0 : document.referrer,
            language: navigator === null || navigator === void 0 ? void 0 : navigator.language,
            description: (_b = document.querySelector('meta[name="description"]')) === null || _b === void 0 ? void 0 : _b.getAttribute("content"),
        };
        if (!requestPayload.apiKey) {
            requestPayload.apiKey = index.Env.DATA_KEY;
        }
        if (!requestPayload.apiKey)
            throw new Error(`Public Key is required. Please provide using attribute "data-key".`);
        const payloadWithoutApiKey = Object.assign(Object.assign({}, requestPayload), { meta });
        delete payloadWithoutApiKey.apiKey;
        const response = await fetch(url, {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "x-api-key": requestPayload.apiKey,
            },
            body: JSON.stringify(payloadWithoutApiKey),
        });
        if (!response.ok) {
            throw await buildResponseError(response);
        }
        const jsonResponse = await response.json();
        return await jsonResponse;
    }
    catch (error) {
        throw error;
    }
}
async function apiGet(url, params = {}, options = {}) {
    try {
        const { requireKeyName = true } = options;
        const requestParams = Object.assign({}, params);
        if (!requestParams.apiKey) {
            requestParams.apiKey = index.Env.DATA_KEY;
        }
        if (!requestParams.apiKey)
            throw new Error(`Public Key is required. Please provide using attribute "data-key".`);
        if (requireKeyName && !requestParams.keyName)
            throw new Error(`Either Key Name or ID is required.`);
        const searchParams = new URLSearchParams();
        Object.entries(requestParams).forEach(([key, value]) => {
            if (key === "apiKey")
                return;
            if (value === undefined || value === null || value === "")
                return;
            searchParams.append(key, typeof value === "object" ? JSON.stringify(value) : String(value));
        });
        const finalUrl = searchParams.toString() ? `${url}?${searchParams.toString()}` : url;
        const response = await fetch(finalUrl, {
            method: "GET",
            headers: {
                "Content-Type": "application/json",
                "x-api-key": requestParams.apiKey,
            },
        });
        if (!response.ok) {
            throw await buildResponseError(response);
        }
        const contentType = response.headers.get("content-type") || "";
        if (contentType.includes("application/json")) {
            return await response.json();
        }
        return await response.text();
    }
    catch (error) {
        throw error;
    }
}
async function submitForm(apiKey, env, keyName, formData, controlType) {
    const endpoint = `${getPaprikaEndpoint(env)}/api/projects/formSubmission`;
    const data = {
        apiKey,
        keyName,
        data: formData,
        controlType,
    };
    return await apiFetch(endpoint, data);
}
async function getSpeechToText(apiKey, lang, env, audioBase64) {
    const speechToText = `${getEndpoint(env)}/bot/audio/transcribe`;
    return await apiFetch(speechToText, { apiKey, language: lang, audioBase64 });
}
async function getFormByKeyName(apiKey, env, keyName) {
    const formEndpoint = `${getPaprikaEndpoint(env)}/api/projects/formSubmission`;
    return await apiGet(formEndpoint, { apiKey, keyName });
}
async function getWidgetContentByType(apiKey, env, keyName, parameters) {
    const endpoint = `${getEndpoint(env)}/bot/control`;
    let parsedParameters = {};
    if (typeof parameters === "string" && parameters.trim() !== "") {
        try {
            parsedParameters = JSON.parse(parameters);
        }
        catch (_error) {
            console.warn("Invalid widget parameters JSON. Falling back to empty object.");
        }
    }
    const data = {
        apiKey,
        keyName,
        parameters: parsedParameters,
    };
    return await apiFetch(endpoint, data);
}
async function getKBContent(apiKey, env, kbId) {
    const getKBContentEndpoint = `${getPaprikaEndpoint(env)}/api/projects/kb/${encodeURIComponent(kbId)}`;
    // kbId is already encoded in the path — no keyName query param is needed or expected.
    return await apiGet(getKBContentEndpoint, { apiKey }, { requireKeyName: false });
}
async function search(apiKey, env, terms) {
    if (!terms)
        return [];
    try {
        const endpoint = `${getEndpoint(env)}/bot/search`;
        const data = {
            apiKey,
            query: terms,
            num_docs: 4,
        };
        return await apiFetch(endpoint, data);
    }
    catch (error) {
        if (getBackendProtocol(env) === "v2") {
            console.warn("Search endpoint not available on v2 backend");
            return [];
        }
        throw error;
    }
}
async function getAudioContent(apiKey, env, content, voiceType) {
    try {
        const endpoint = `${getEndpoint(env)}/bot/synthesize`;
        const data = {
            text: content,
            apiKey: apiKey,
            voiceType: voiceType,
        };
        return await apiFetch(endpoint, data);
    }
    catch (error) {
        if (getBackendProtocol(env) === "v2") {
            console.warn("Synthesize endpoint not available on v2 backend");
            return null;
        }
        throw error;
    }
}
function base64ToBlob(base64, mimeType) {
    const byteCharacters = atob(base64);
    const byteNumbers = new Array(byteCharacters.length).fill(0).map((_, i) => byteCharacters.charCodeAt(i));
    const byteArray = new Uint8Array(byteNumbers);
    return new Blob([byteArray], { type: mimeType });
}
// Method to remove HTML tags from a string
function removeHtmlTags(text) {
    const div = document.createElement("div");
    div.innerHTML = text;
    return div.textContent || div.innerText || "";
}
async function sendFeedback(apiKey, env, insightId, feedback) {
    if (!insightId)
        return; // v2 backend may not provide insightId
    try {
        const endpoint = `${getEndpoint(env)}/bot/feedback`;
        const data = {
            apiKey,
            insight_id: insightId,
            feedback,
        };
        return await apiFetch(endpoint, data);
    }
    catch (error) {
        if (getBackendProtocol(env) === "v2") {
            console.warn("Feedback endpoint not available on v2 backend");
            return;
        }
        throw error;
    }
}
function debounce(func, timeout = 300) {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(this, args);
        }, timeout);
    };
}
async function checkStatus(apiKey, env) {
    if (isAI12ZControlEnabled === null) {
        try {
            const endpoint = `${getEndpoint(env)}/bot/status`;
            const res = await apiFetch(endpoint, { apiKey });
            if (res) {
                isAI12ZControlEnabled = res.enable;
            }
        }
        catch (error) {
            isAI12ZControlEnabled = false;
        }
    }
    return isAI12ZControlEnabled;
}
function generateUUID() {
    return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
        var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
        return v.toString(16);
    });
}
function updateButtonEvents(htmlContent) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(htmlContent, "text/html");
    const buttons = Array.from(doc.querySelectorAll("button"));
    let customButtons = buttons.map((button, index) => {
        const id = button.id || `button-${index}`;
        const label = button.textContent || `Button ${index + 1}`;
        button.id = id;
        const originalClickHandler = button.getAttribute("onclick");
        button.removeAttribute("type");
        button.removeAttribute("onclick");
        if (originalClickHandler) {
            button.setAttribute("data-original-click", originalClickHandler);
        }
        button.setAttribute("aria-label", label);
        return {
            id,
            label,
            // originalClickHandler,
            // onClick: originalOnClick,
            onClick: () => alert(`Button ${id} clicked!`),
        };
    });
    // console.log("customButtons", customButtons)
    // Update the htmlContent with the modified buttons
    return { body: doc.body.innerHTML, buttons: customButtons };
}
function getConfig(payload, env) {
    const { configId, apiKey, configType } = payload;
    const endpoint = `${getEndpoint(env)}/bot/config`;
    if (!payload.apiKey) {
        payload.apiKey = index.Env.DATA_KEY;
    }
    const data = {
        configId,
        apiKey,
        configType,
    };
    return apiFetch(endpoint, data);
}
function verifyRecaptcha(payload, env) {
    const endpoint = `${getEndpoint(env)}/bot/verify`;
    if (!payload.apiKey) {
        payload.apiKey = index.Env.DATA_KEY;
    }
    return apiFetch(endpoint, payload);
}
function getOrCreateVisitorId() {
    const visitorIdKey = "ai12z-visitorId";
    let visitorId = localStorage.getItem(visitorIdKey);
    if (!visitorId) {
        visitorId = generateVisitorId();
        localStorage.setItem(visitorIdKey, visitorId);
    }
    return "ai12z-" + visitorId;
}
function generateVisitorId() {
    return Date.now() + "-" + Math.random().toString(36).substr(2, 9);
}
function getComponentByControlType(data, inputType) {
    var _a, _b, _c, _d, _e, _f;
    const controlType = (_b = (_a = data.controlData) === null || _a === void 0 ? void 0 : _a.data.source.carousel) === null || _b === void 0 ? void 0 : _b.type;
    const listElement = document.createElement("item-list");
    // listElement.items = data.controlData?.data.source.items
    // listElement.itemsPerPage = data.controlData?.data.source?.carousel?.itemPerPage
    // listElement.emptyMessage = data.controlData?.data.source?.carousel?.emptyMessage
    // listElement.formSettings = data.controlData?.data.source?.formSettings
    // listElement.buttonText = data.controlData?.data.source?.carousel?.buttonText
    listElement.carouselType = controlType;
    listElement.inputType = inputType;
    listElement.customTemplate = data.controlData.template;
    listElement.customSource = (_c = data.controlData) === null || _c === void 0 ? void 0 : _c.data.source;
    listElement.llm = (_d = data.controlData) === null || _d === void 0 ? void 0 : _d.data.llm;
    listElement.isExpanded = data.isExpanded || false;
    listElement.customStyles = ((_e = data.controlData) === null || _e === void 0 ? void 0 : _e.styles) || "";
    listElement.customScripts = ((_f = data.controlData) === null || _f === void 0 ? void 0 : _f.scripts) || "";
    return listElement;
}
function getBotTemplate(type) {
    switch (type) {
        case "list":
            const listTemplate = [
                {
                    name: "list",
                    content: `{{#each items as |item index|}}
  <div class="carousel-card flex flex-col items-start mb-4 bg-white border h-auto border-gray-200 rounded-lg shadow md:flex-row md:max-w-xl  dark:border-gray-700" data-index="{{@index}}">
    <div class="relative carousel-container card-image {{#if (gte item.images.length  1)}}w-full{{else}}w-1/2{{/if}}" data-carousel-id="carousel-{{index}}" id="carousel-{{index}}" data-carousel="slide">
          <div class="relative h-64 overflow-hidden">
          {{#each item.images as |image imageIndex|}}      
            <img src="{{this}}" alt="Image for {{../title}}" class="card-image object-cover w-full h-96 md:h-auto md:mt-6 md:ml-2 hidden duration-700 ease-in-out"  data-carousel-item id="carousel-{{index}}-item-{{imageIndex}}"/>    
          {{/each}}
          </div>  
        {{#if (lte item.images.length 3)}} 
            {{#if (gte item.images.length 1)}}
              <div class="absolute z-30 flex -translate-x-1/2 bottom-5 left-1/2 space-x-3 rtl:space-x-reverse">
                {{#each images as |image imageIndex|}}
                  <button type="button" class="w-3 h-3 rounded-full" aria-current="true" aria-label="Slide {{@index}}" data-carousel-slide-to="{{index}}"  id="carousel-{{index}}-indicator-{{imageIndex}}"></button>
                {{/each}}
              </div>
            {{/if}}
          {{else}}
           <div class="absolute z-30 flex -translate-x-1/2 bottom-5 left-1/2 space-x-3 rtl:space-x-reverse">
                <button type="button" class="w-3 h-3 rounded-full bg-blue-600" aria-current="true" aria-label="Slide {{@index}}" data-carousel-prev  id="carousel-{{index}}-prev"></button>
                <button type="button" class="w-3 h-3 rounded-full bg-blue-600" aria-current="true" aria-label="Slide {{@index}}" data-carousel-next  id="carousel-{{index}}-next"></button>
            </div>
        {{/if}}
  </div>
      
    <div class="flex flex-col justify-between p-4 leading-normal">
        <h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white"> {{{this.title}}}</h5>
        {{#each subTitle}}       
          <p class="font-title text-md md:text-xl">{{this}}</p>      
        {{/each}}
        <p class="short-description mb-3 font-normal text-gray-700 dark:text-gray-400">{{{this.shortDescription}}}</p>
        <div class="long-description mb-3 font-normal text-gray-700 dark:text-gray-400 hidden">{{{this.description}}}</div>
        {{#if this.description}}
          <button  class="read-more text-blue-500 hover:text-blue-700 underline focus:outline-none"  data-index="{{@index}}"> Read More </button>
        {{/if}}
        <div class="flex flex-col items-center my-4">
            {{#each buttons}}      
              <button class="card-button list-btn uppercase pt-2 pb-1 px-4 flex-grow hover:bg-gradient-to-t md:flex-none" data-id="{{@index}}" data-url="{{this.url}}" data-type="{{this.type}}">
               {{this.label}}</button>
            {{/each}}
            {{#and ../buttonText formSettings}}
              <button class="card-button list-btn uppercase" data-type="panel">{{../buttonText}}</button>
            {{/and}}
        </div>
    </div>
</div>
{{/each}}
<div class="pagination-controls">
<button class="prev-btn list-btn" {{#unless hasPrev}}disabled{{/unless}}>Prev</button>
<span> Page {{getcurrentPage}} of {{getPageCount}} </span>
<button class="next-btn list-btn" {{#unless hasNext}}disabled{{/unless}}>Next</button>
</div>`,
                },
                {
                    name: "detail",
                    content: `<div class="flex flex-col items-center justify-center w-full h-full p-4">
          <div class="w-full md:col-span-2 h-fit">
            <dynamic-form form="{{json form}}" formSettings="{{json formSettings}}" theme="{{json theme}}"/>
          </div>   
          <div>    
            {{#each buttons}}    
              <button class="panel-button list-btn text-white" data-id="{{this.index}}" data-type="{{this.type}}">{{this.label}}</button>     
            {{/each}}
          </div>
          </div>`,
                },
            ];
            return listTemplate;
    }
}
function getTemplate(type) {
    switch (type) {
        case "list":
            const tempalteArray = [
                {
                    name: "list",
                    content: `{{#each items as |item index|}}
  <div class="carousel-card flex flex-col items-start mb-4 bg-white border h-auto border-gray-200 rounded-lg shadow md:flex-row  dark:border-gray-700" data-index="{{index}}">
  
  <div class="relative  md:w-1/3 carousel-container card-image {{#if (gte item.images.length  1)}}w-full{{else}}w-full md:w-1/2{{/if}}" data-carousel-id="carousel-{{index}}" id="carousel-{{index}}" data-carousel="slide">
          <div class="relative h-64 overflow-hidden">
          {{#each item.images as |image imageIndex|}}      
            <img src="{{this}}" alt="Image for {{../title}}" class="card-image object-cover w-full h-96 md:h-auto md:mt-6 md:ml-2 hidden duration-700 ease-in-out"  data-carousel-item id="carousel-{{index}}-item-{{imageIndex}}"/>    
          {{/each}}
          </div>  
        {{#if (lte item.images.length 3)}} 
            {{#if (gte item.images.length 1)}}
              <div class="absolute z-30 flex -translate-x-1/2 bottom-5 left-1/2 space-x-3 rtl:space-x-reverse">
                {{#each images as |image imageIndex|}}
                  <button type="button" class="w-3 h-3 rounded-full" aria-current="true" aria-label="Slide {{@index}}" data-carousel-slide-to="{{index}}"  id="carousel-{{index}}-indicator-{{imageIndex}}"></button>
                {{/each}}
              </div>
            {{/if}}
          {{else}}
           <div class="absolute z-30 flex -translate-x-1/2 bottom-5 left-1/2 space-x-3 rtl:space-x-reverse">
                <button type="button" class="w-3 h-3 rounded-full bg-blue-600" aria-current="true" aria-label="Slide {{@index}}" data-carousel-prev  id="carousel-{{index}}-prev"></button>
                <button type="button" class="w-3 h-3 rounded-full bg-blue-600" aria-current="true" aria-label="Slide {{@index}}" data-carousel-next  id="carousel-{{index}}-next"></button>
            </div>
        {{/if}}
  </div>
   
  
   
    <div class="flex flex-col justify-between p-4 leading-normal md:w-2/3 card-right">
        <h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white"> {{{this.title}}}</h5>
        {{#each subTitle}}       
          <p class="font-title text-md md:text-xl">{{this}}</p>      
        {{/each}}
        <p class="short-description mb-3 font-normal text-gray-700 dark:text-gray-400">{{{this.shortDescription}}}</p>
        <div class="long-description mb-3 font-normal text-gray-700 dark:text-gray-400 hidden">{{{this.description}}}</div>
        {{#if this.description}}
          <a  class="read-more text-blue-500 hover:text-blue-700 underline focus:outline-none"  data-index="{{@index}}"> Read More </a>
        {{/if}}
        <div class="flex items-center my-4">
            {{#each buttons as |button buttonIndex|}}      
              <button class="card-button list-btn uppercase pt-2 pb-1 px-4 flex-grow hover:bg-gradient-to-t md:flex-none" data-id="{{buttonIndex}}" data-url="{{this.url}}" data-type="{{this.type}}">
               {{this.label}}</button>
            {{/each}}
           {{#and ../buttonText formSettings}}
              <button class="card-button list-btn uppercase" data-type="panel">{{../buttonText}}</button>
            {{/and}}
        </div>
    </div>
</div>
{{/each}}
<div class="pagination-controls">
<button class="prev-btn list-btn" {{#unless hasPrev}}disabled{{/unless}}>Prev</button>
<span> Page {{getcurrentPage}} of {{getPageCount}} </span>
<button class="next-btn list-btn" {{#unless hasNext}}disabled{{/unless}}>Next</button>
</div>
`,
                },
                {
                    name: "detail",
                    content: `
          <div class="flex flex-col items-center justify-center w-full h-full p-4">
          <div class="w-full md:col-span-2 h-fit">
            <dynamic-form form="{{json form}}" formSettings="{{json formSettings}}" theme="{{theme}}"/>
          </div>   
          <div>    
            {{#each buttons}}    
              <button class="panel-button list-btn text-white" data-id="{{this.index}}" data-type="{{this.type}}">{{this.label}}</button>     
            {{/each}}
          </div>
          </div>`,
                },
            ];
            return tempalteArray;
        case "slider":
            const sliderArray = [
                {
                    name: "carousel",
                    content: `
<div id="carouselExample" class="relative w-full" data-carousel="static">
  
            <div class="carousel-box relative bg-white overflow-hidden overflow-y-scroll h-56 rounded-lg md:h-96" style={ overflowY: "scroll", height: "30rem" }>
              {{#each items as |item index|}}
                  <div class="carousel-card max-w-sm hidden duration-700 ease-in-out md:max-w-xl" data-carousel-item id="carousel-item-{{index}}" data-index="{{index}}">
                     <div class="card-image relative w-full carousel-container" data-carousel-id="carousel-{{index}}" id="carousel-{{index}}" data-carousel="slide">
                        <div class="relative h-64 overflow-hidden rounded-lg">
                          {{#each item.images as |image imageIndex|}} 
                    
                              <img src="{{this}}" alt="Image for {{../title}}" class="card-image object-cover h-96  hidden duration-700 ease-in-out"  data-carousel-item id="carousel-{{index}}-item-{{imageIndex}}"/>    
                            
                          {{/each}}
                        </div> 
                    {{#if (lte item.images.length 3)}} 
                        <div class="absolute z-30 flex -translate-x-1/2 bottom-5 left-1/2 space-x-3 rtl:space-x-reverse">
                          {{#each images as |image imageIndex|}}
                            <button type="button" class="w-3 h-3 rounded-full" aria-current="true" aria-label="Slide {{@index}}" data-carousel-slide-to="{{index}}"  id="carousel-{{index}}-indicator-{{imageIndex}}"></button>
                          {{/each}}
                        </div>
                        {{else}}
                          <div class="absolute z-30 flex -translate-x-1/2 bottom-5 left-1/2 space-x-3 rtl:space-x-reverse">
                              <button type="button" class="w-3 h-3 rounded-full bg-blue-600" aria-current="true" aria-label="Slide {{@index}}" data-carousel-prev  id="carousel-{{index}}-prev"></button>
                              <button type="button" class="w-3 h-3 rounded-full bg-blue-600" aria-current="true" aria-label="Slide {{@index}}" data-carousel-next  id="carousel-{{index}}-next"></button>
                          </div>
                      {{/if}}
                    </div>  
                 
                  <div class="p-5">
                      <a href="#">
                          <h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">{{{title}}}</h5>
                      </a>
                      <p class="short-description mb-3 font-normal text-gray-700 dark:text-gray-400">{{{shortDescription}}}</p>
                      <div class="long-description mb-3 font-normal text-gray-700 dark:text-gray-400 hidden">{{{description}}}</div>
                      {{#if description}}
                        <a class="read-more inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
                            Read more
                            <svg class="rtl:rotate-180 w-3.5 h-3.5 ms-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
                                <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5h12m0 0L9 1m4 4L9 9"/>
                            </svg>
                        </a>
                      {{/if}}
                      {{#each buttons}}
                      <button class="card-button list-btn uppercase pt-2 pb-1 px-4 flex-grow hover:bg-gradient-to-t md:flex-none" data-index="{{@index}}" data-url="{{this.url}}" data-type="{{this.type}}">{{this.label}}</button>
                      {{/each}}
                  </div>
                </div>
              {{/each}}
            </div>

        <div class="absolute z-30 flex overflow-x-auto -translate-x-1/2 space-x-1 rtl:space-x-reverse bottom-5 left-1/2 scrollbar-visible">
        {{#if (lte items.length 5)}}  
          {{#each items}}
              <button
                  id="carousel-indicator-{{@index}}"
                  type="button"
                  class="w-2.5 h-2.5 sm:w-3 sm:h-3 md:w-4 md:h-4 rounded-full"
                  aria-current="true"
                  aria-label="Slide {{@index}}"
              ></button>
          {{/each}}
        {{/if}}
      </div>

  <!-- Controls -->
  <button
    type="button"
    class="absolute top-0 left-0 z-30 flex items-center justify-center h-full px-4 cursor-pointer group focus:outline-none"
    id="data-carousel-prev"
    data-carousel-prev
  >
    <span
      class="inline-flex items-center justify-center w-10 h-10 rounded-full bg-blue-600"
    >
      <svg
        aria-hidden="true"
        class="w-6 h-6 text-white"
        fill="none"
        stroke="currentColor"
        viewBox="0 0 24 24"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          stroke-linecap="round"
          stroke-linejoin="round"
          stroke-width="2"
          d="M15 19l-7-7 7-7"
        ></path>
      </svg>
      <span class="sr-only">Previous</span>
    </span>
  </button>
  <button
    type="button"
    class="absolute top-0 right-0 z-30 flex items-center justify-center h-full px-4 cursor-pointer group focus:outline-none"
    id="data-carousel-next"
    data-carousel-next
  >
    <span
      class="inline-flex items-center justify-center w-10 h-10 rounded-full bg-blue-600"
    >
      <svg
        aria-hidden="true"
        class="w-6 h-6 text-white dark:text-gray-800"
        fill="none"
        stroke="currentColor"
        viewBox="0 0 24 24"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          stroke-linecap="round"
          stroke-linejoin="round"
          stroke-width="2"
          d="M9 5l7 7-7 7"
        ></path>
      </svg>
      <span class="sr-only">Next</span>
    </span>
  </button>
</div>`,
                },
                {
                    name: "detail",
                    content: `
          <div class="flex flex-col items-center justify-center w-full h-full p-4">
          <div class="w-full md:col-span-2 h-fit">
            <dynamic-form form="{{json form}}" formSettings="{{json formSettings}}" theme="{{theme}}"/>
          </div>   
          <div>    
            {{#each buttons}}    
              <button class="panel-button list-btn text-white" data-id="{{this.index}}" data-type="{{this.type}}">{{this.label}}</button>     
            {{/each}}
          </div>
          </div>`,
                },
            ];
            return sliderArray;
    }
}
function getBroswerLang() {
    const browserLang = navigator.language || navigator["userLanguage"];
    const normalizedLang = browserLang.split("-")[0]; // e.g., "en-US" → "en"
    return normalizedLang;
}
function getAllLanguagesInSurvey(surveyJson) {
    const langs = new Set();
    function isMultiLangObject(obj) {
        return typeof obj === "object" && obj !== null && Object.keys(obj).length > 0 && Object.values(obj).every(value => typeof value === "string");
    }
    function extractLangs(obj) {
        if (Array.isArray(obj)) {
            obj.forEach(item => extractLangs(item));
        }
        else if (typeof obj === "object" && obj !== null) {
            if (isMultiLangObject(obj) && Object.keys(obj).includes("default")) {
                Object.keys(obj).forEach(key => langs.add(key));
            }
            for (const key in obj) {
                extractLangs(obj[key]);
            }
        }
    }
    extractLangs(surveyJson);
    return langs;
}
function isString(val) {
    return typeof val === "string";
}
function isObject(value) {
    return typeof value === "object" && value !== null;
}
function customOptions(context, options) {
    var defaults = context && context.options ? context.options : {};
    return Object.assign({}, defaults, options.hash);
}
function chop(str) {
    if (!isString(str))
        return "";
    var re = /^[-_.\W\s]+|[-_.\W\s]+$/g;
    // console.log("chop", str, re)
    return str.trim().replace(re, "");
}
function changecase(str, fn) {
    if (!isString(str))
        return "";
    if (str.length === 1) {
        return str.toLowerCase();
    }
    str = chop(str).toLowerCase();
    if (typeof fn !== "function") {
        fn = function identity(x) {
            return x;
        };
    }
    var re = /[-_.\W\s]+(\w|$)/g;
    return str.replace(re, function (_, ch) {
        return fn(ch);
    });
}
function isOptions(val) {
    return isObject(val) && isObject(val.hash);
}
function isUndefined(val) {
    return val == null || (isOptions(val) && val.hash != null);
}
function indexOf(array, value) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i] === value) {
            return i;
        }
    }
    return -1;
}
function utilValue(val, context, options) {
    if (isOptions(val)) {
        return utilValue(null, val, options);
    }
    if (isOptions(context)) {
        return utilValue(val, {}, context);
    }
    if (isBlock(options)) {
        return !!val ? options.fn(context) : options.inverse(context);
    }
    return val;
}
function isBlock(options) {
    return isOptions(options) && typeof options.fn === "function" && typeof options.inverse === "function";
}
function utilResult(val) {
    if (typeof val === "function") {
        return val.apply(this, [].slice.call(arguments, 1));
    }
    return val;
}
function updateAnchorTags(htmlContent, linkTarget, className, utmConfig, linkType) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(htmlContent, "text/html");
    const anchorTags = Array.from(doc.querySelectorAll("a"));
    anchorTags.forEach(anchor => {
        anchor.setAttribute("target", linkTarget);
        anchor.classList.add(className !== null && className !== void 0 ? className : "ai12z-link");
        // Apply UTM parameters if config is provided
        if (utmConfig) {
            applyUTMToLink(anchor, utmConfig, linkType);
        }
    });
    return doc.body.innerHTML;
}
function applyUTMToLink(anchor, utmConfig, linkType) {
    // Normalize config - support both old (direct values) and new (full config) format
    let config;
    if ('enabled' in utmConfig || 'values' in utmConfig || 'applyTo' in utmConfig || 'behavior' in utmConfig) {
        // New format with full configuration
        config = utmConfig;
    }
    else {
        // Old format - just values object
        config = {
            enabled: true,
            values: utmConfig,
            behavior: {
                existingUtmHandling: 'skip',
                ignoreEmpty: true,
                lowercaseKeys: false,
                urlEncode: true
            }
        };
    }
    // Check if UTM is enabled
    if (config.enabled === false) {
        return;
    }
    // Check if we should apply to this link type
    if (config.applyTo && linkType) {
        const shouldApply = config.applyTo[`${linkType}Links`];
        if (shouldApply === false) {
            return;
        }
    }
    const href = anchor.getAttribute("href");
    if (!href || href.startsWith("#") || href.startsWith("javascript:") || href.startsWith("mailto:") || href.startsWith("tel:")) {
        return;
    }
    try {
        const url = new URL(href, window.location.origin);
        const values = config.values || {};
        const behavior = config.behavior || {};
        // Check if URL already has UTM parameters
        const hasExistingUtm = Array.from(url.searchParams.keys()).some(key => key.toLowerCase().startsWith('utm_'));
        if (hasExistingUtm && behavior.existingUtmHandling === 'skip') {
            return; // Skip this link entirely
        }
        // Process each UTM parameter
        Object.keys(values).forEach(key => {
            const value = values[key];
            // Skip empty values if ignoreEmpty is true
            if (behavior.ignoreEmpty && (!value || value.trim() === '')) {
                return;
            }
            // Apply key transformations
            let paramKey = key;
            if (behavior.lowercaseKeys) {
                paramKey = paramKey.toLowerCase();
            }
            // URLSearchParams.set() automatically handles URL encoding, so we use the value directly
            let paramValue = value;
            // Check existing UTM handling behavior
            if (behavior.existingUtmHandling === 'merge') {
                // Only add if this specific key doesn't exist
                if (!url.searchParams.has(paramKey)) {
                    url.searchParams.set(paramKey, paramValue);
                }
            }
            else if (behavior.existingUtmHandling === 'overwrite') {
                // Always overwrite
                url.searchParams.set(paramKey, paramValue);
            }
            else {
                // Default behavior (when no existing UTM params)
                url.searchParams.set(paramKey, paramValue);
            }
        });
        anchor.setAttribute("href", url.toString());
    }
    catch (error) {
        console.warn("Failed to parse URL for UTM parameters:", href, error);
    }
}
/**
 * Calculate the size of a string in bytes (UTF-8 encoding)
 */
function getStringSize(str) {
    return new Blob([str]).size;
}
/**
 * Get the current size of localStorage in bytes
 */
function getLocalStorageSize() {
    let totalSize = 0;
    for (const key in localStorage) {
        if (localStorage.hasOwnProperty(key)) {
            const value = localStorage.getItem(key) || "";
            totalSize += getStringSize(key + value);
        }
    }
    return totalSize;
}
function formatTimestamp(date) {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const options = {
        weekday: "long",
        hour: "numeric",
        minute: "numeric",
        hour12: true,
    };
    const formatter = new Intl.DateTimeFormat("en-US", options);
    const formattedDate = formatter.format(date);
    if (date.toDateString() === today.toDateString()) {
        return `Today, ${formattedDate.split(" ").slice(1).join(" ")}`;
    }
    else {
        return formattedDate;
    }
}
function generateMessage(conversationId) {
    return {
        text: "",
        isUser: false,
        id: `chatbot-${generateUUID()}`,
        isLoading: true,
        timestamp: new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
        images: [],
        conversationId,
        formModel: {},
        surveyDomId: "",
    };
}
/**
 * Clean up old conversations based on date to free up storage space
 * @param conversations Array of conversations to clean up
 * @param maxSizeBytes Maximum size in bytes before cleanup
 * @returns Cleaned up conversations array
 */
function cleanupOldConversations(conversations, maxSizeBytes = 2 * 1024 * 1024) {
    const currentSize = getLocalStorageSize();
    // If we're under the size limit, no cleanup needed
    if (currentSize <= maxSizeBytes) {
        return conversations;
    }
    // Sort conversations by date (oldest first) for cleanup
    const sortedConversations = [...conversations].sort((a, b) => {
        const dateA = new Date(a.date).getTime();
        const dateB = new Date(b.date).getTime();
        return dateA - dateB;
    });
    let cleanedConversations = [...sortedConversations];
    let estimatedSize = getStringSize(JSON.stringify(cleanedConversations));
    // Remove oldest conversations until we're under the size limit
    while (estimatedSize > maxSizeBytes && cleanedConversations.length > 1) {
        cleanedConversations.shift();
        estimatedSize = getStringSize(JSON.stringify(cleanedConversations));
    }
    // If we still have size issues, clean up old messages from remaining conversations
    if (estimatedSize > maxSizeBytes) {
        cleanedConversations = cleanedConversations.map(conversation => {
            if (conversation.messages && conversation.messages.length > 10) {
                // Keep only the last 10 messages in each conversation
                conversation.messages = conversation.messages.slice(-10);
            }
            return conversation;
        });
    }
    return cleanedConversations;
}
// ✅ Enhanced function to split content with multiple [control] elements
function splitContentMultiple(content) {
    const controls = [];
    const parts = [];
    let currentIndex = 0;
    // Find all [control] patterns
    const controlRegex = /\[control[^\]]*\]/g;
    let match;
    while ((match = controlRegex.exec(content)) !== null) {
        // Add text before this control
        const beforeText = content.substring(currentIndex, match.index);
        if (isValidTextContent(beforeText)) {
            parts.push({
                type: "text",
                content: beforeText,
            });
        }
        // Add the control
        const controlText = match[0];
        const agentDataIdMatch = controlText.match(/agentDataId="([^"]*)"/);
        const typeMatch = controlText.match(/type="([^"]*)"/);
        controls.push({
            type: "control",
            content: controlText,
            agentDataId: agentDataIdMatch ? agentDataIdMatch[1] : null,
            controlType: typeMatch ? typeMatch[1] : "carousel",
        });
        parts.push({
            type: "control",
            content: controlText,
            agentDataId: agentDataIdMatch ? agentDataIdMatch[1] : null,
            controlType: typeMatch ? typeMatch[1] : "carousel",
        });
        currentIndex = match.index + match[0].length;
    }
    // Add remaining text after the last control
    const remainingText = content.substring(currentIndex);
    if (isValidTextContent(remainingText)) {
        parts.push({
            type: "text",
            content: remainingText,
        });
    }
    return {
        parts,
        controls,
        hasControls: controls.length > 0,
        controlCount: controls.length,
    };
}
// ✅ Helper function to check if text content is valid (not empty, not just <p></p>)
function isValidTextContent(text) {
    if (!text)
        return false;
    // Remove whitespace
    const trimmed = text.trim();
    if (!trimmed)
        return false;
    // Check for empty paragraph tags (various forms)
    const emptyParagraphPatterns = [
        /^<p><\/p>$/, // <p></p>
        /^<p>\s*<\/p>$/, // <p> </p> (with whitespace)
        /^<p>&nbsp;<\/p>$/, // <p>&nbsp;</p>
        /^<p><br><\/p>$/, // <p><br></p>
        /^<p><br\/><\/p>$/, // <p><br/></p>
        /^<br\s*\/?>$/, // Just <br> or <br/>
        /^&nbsp;$/, // Just &nbsp;
        /^\s*$/,
    ];
    // Check if the text matches any empty pattern
    for (const pattern of emptyParagraphPatterns) {
        if (pattern.test(trimmed)) {
            return false;
        }
    }
    // ✅ More comprehensive check: strip all HTML tags and check if there's actual content
    const textOnly = trimmed
        .replace(/<[^>]*>/g, "")
        .replace(/&nbsp;/g, " ")
        .trim();
    if (!textOnly) {
        return false;
    }
    return true;
}
async function getSessionState(stateName) {
    return sessionStorage.getItem(stateName);
}
async function insertStyles(linkURL, element) {
    if (!isValidHttpsUrl(linkURL)) {
        console.warn(`Invalid URL provided for styles: ${linkURL}. Styles will not be applied.`);
        return;
    }
    const linkEl = document.createElement("link");
    linkEl.setAttribute("rel", "stylesheet");
    linkEl.setAttribute("href", linkURL);
    const shadowRoot = element.shadowRoot;
    if (shadowRoot) {
        shadowRoot.appendChild(linkEl);
    }
}
/**
 * Returns true only when the URL uses the https: protocol.
 * Rejects relative URLs, protocol-relative URLs, javascript: / data: URIs,
 * and any other non-HTTPS scheme.
 */
function isValidHttpsUrl(url) {
    if (!url || typeof url !== "string")
        return false;
    try {
        const parsed = new URL(url);
        return parsed.protocol === "https:";
    }
    catch (_a) {
        return false;
    }
}

exports.base64ToBlob = base64ToBlob;
exports.changecase = changecase;
exports.checkStatus = checkStatus;
exports.chop = chop;
exports.cleanupOldConversations = cleanupOldConversations;
exports.customOptions = customOptions;
exports.debounce = debounce;
exports.formatTimestamp = formatTimestamp;
exports.generateMessage = generateMessage;
exports.generateUUID = generateUUID;
exports.getAllLanguagesInSurvey = getAllLanguagesInSurvey;
exports.getAudioContent = getAudioContent;
exports.getBackendProtocol = getBackendProtocol;
exports.getBotTemplate = getBotTemplate;
exports.getBroswerLang = getBroswerLang;
exports.getComponentByControlType = getComponentByControlType;
exports.getConfig = getConfig;
exports.getEndpoint = getEndpoint;
exports.getFormByKeyName = getFormByKeyName;
exports.getKBContent = getKBContent;
exports.getMetaInfo = getMetaInfo;
exports.getOrCreateVisitorId = getOrCreateVisitorId;
exports.getSessionState = getSessionState;
exports.getSpeechToText = getSpeechToText;
exports.getTemplate = getTemplate;
exports.getWidgetContentByType = getWidgetContentByType;
exports.indexOf = indexOf;
exports.insertStyles = insertStyles;
exports.isObject = isObject;
exports.isOptions = isOptions;
exports.isString = isString;
exports.isUndefined = isUndefined;
exports.isValidHttpsUrl = isValidHttpsUrl;
exports.removeHtmlTags = removeHtmlTags;
exports.search = search;
exports.sendFeedback = sendFeedback;
exports.splitContentMultiple = splitContentMultiple;
exports.submitForm = submitForm;
exports.updateAnchorTags = updateAnchorTags;
exports.updateButtonEvents = updateButtonEvents;
exports.utilResult = utilResult;
exports.utilValue = utilValue;
exports.verifyRecaptcha = verifyRecaptcha;
