/**
 * WordPress localize object mapped to a constant.
 */
const _wccStore = window._wccConfig;
const _wccStyle = window._wccStyles;
// Define currentLaw as a global variable
let currentLaw =  window._wccConfig._lawSelected[0];

// Iniitialize showBanner as true
let showBanner = true;
_wccStore._backupNodes = [];
_wccStore._resetConsentID = false;
_wccStore._bannerState = false;
_wccStore._preferenceOriginTag = false;

_wccStore._cookiePath = (function() {
    try {
        const currentPathname = window.location.pathname;
        
        if (_wccStore._publicURL) {
            try {
                const publicURL = new URL(_wccStore._publicURL);
                const publicPathname = publicURL.pathname.replace(/\/+$/, '');
                
                if (publicPathname && publicPathname !== '/' && currentPathname.startsWith(publicPathname)) {
                    return publicPathname + '/';
                }
            } catch (e) {
                // Ignore parsing errors
            }
        }
        
        return '/';
    } catch (e) {
        console.warn('Failed to detect cookie path:', e);
        return '/';
    }
})();

window.webtoffee = window.webtoffee || {};
const ref = window.webtoffee;
ref._wccConsentStore = new Map();

ref._wccGetCookieMap = function () {
    const cookieMap = {};
    try {
        document.cookie.split(";").forEach((cookie) => {
            const [key, value] = cookie.split("=");
            if (!key) return;
            const trimmedKey = key.trim();
            
            if (trimmedKey === 'wt_consent' && cookieMap[trimmedKey]) {
                return;
            }
            
            cookieMap[trimmedKey] = value;
        });
    } catch (error) { }
    return cookieMap;
};

const currentCookieMap = ref._wccGetCookieMap();

ref._wccGetFromStore = function (key) {
    return ref._wccConsentStore.get(key) || "";
};

ref._wccSetInStore = function (key, value) {
    ref._wccConsentStore.set(key, value);
    ref._wccConsentStore.set('cookie_path', _wccStore._cookiePath);
    
    const cookieStringArray = Array.from(ref._wccConsentStore, ([k, v]) => `${k}:${v}`);
    const scriptExpiry = _wccStore?._bannerConfig?.[currentLaw]?.settings?.consentExpiry || 365;
    
    ref._wccSetCookie("wt_consent", cookieStringArray.join(","), scriptExpiry);
};

const webtoffeeConsentMap = (currentCookieMap["wt_consent"] || "")
    .split(",")
    .reduce((prev, curr) => {
        if (!curr) return prev;
        const [key, value] = curr.split(":");
        prev[key] = value;
        return prev;
    }, {});

const cookiePath = webtoffeeConsentMap['cookie_path'];
const isCorrectPath = cookiePath 
    ? cookiePath === _wccStore._cookiePath
    : _wccStore._cookiePath === '/' && currentCookieMap["wt_consent"];

const consentKeys = ["consent", "action"].concat(_wccStore._categories.map(({ slug }) => slug));
const consentValue = isCorrectPath ? (item) => webtoffeeConsentMap[item] || "" : () => "";

consentKeys.forEach(item => ref._wccConsentStore.set(item, consentValue(item)));
if (isCorrectPath) {
    ref._wccConsentStore.set('cookie_path', _wccStore._cookiePath);
}
/**
 * Get the value of cookie by it's name.
 * 
 * @param {string} name Name of the cookie
 * @returns {string}
 */
ref._wccGetCookie = function (name) {
    const cookies = document.cookie.split(';');
    for (let i = 0; i < cookies.length; i++) {
        const cookie = cookies[i].trim();
        if (cookie.startsWith(name + '=')) {
            return decodeURIComponent(cookie.substring(name.length + 1));
        }
    }
    return null;
}

/**
 * Set a cookie on document.cookie object.
 * 
 * @param {*} name Name of the cookie.
 * @param {*} value Value to be set.
 * @param {*} days Expiry in days.
 * @param {*} domain Cookie domain.
 * @param {*} ssl SSL enabled.
 * @param {*} path Cookie path (defaults to detected path for multisite support).
 */
ref._wccSetCookie = function (name, value, days = 0, domain = _wccStore._rootDomain, ssl = _wccStore._ssl, path = _wccStore._cookiePath) {
    const date = new Date();
    const domainStr = domain ? `domain=${domain}` : '';
    const sslStr = ssl ? `secure` : '';
    const toSetTime = days === 0 ? 0 : date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
    
    document.cookie = `${name}=${value}; expires=${new Date(toSetTime).toUTCString()}; path=${path};${domainStr}; SameSite=Strict;${sslStr};`;
}

function _wccSetConsentID() {
    const cookieyesID = ref._wccGetFromStore("consentid");
    if (cookieyesID) return;
    const consentID = ref._wccRandomString(32);
    ref._wccSetInStore("consentid", consentID);
    _wccStore._resetConsentID = true;
}
function _wccSetConsentTime() {
    const consentTime = new Date().getTime(); // Get current time if consent time is not available
    ref._wccSetInStore("consent_time", consentTime);
}

function _wccRenewConsent() {
    ref._wccSetInStore("action", "");
}

_revisitWccConsent = function () {
    const type = _wccGetType();
    if (type === 'classic') {
        _wccShowBanner();
    }
    _wccSetPreferenceAction();
    _wccToggleRevisit();
};
/**
 * Search an element by it's data-tag attribute
 * 
 * @param {string} tag data-tag of an element. 
 * @returns {object}
 */
function _wccGetElementByTag(tag) {
    const item = document.querySelector('[data-tag=' + tag + ']');
    return item ? item : false;
}

function _wccEscapeRegex(literal) {
    return literal.replace(/[.*+?^${}()[\]\\]/g, "\\$&");
}

/**
 * Bind click event to banner elements.
 * 
 * @param {string} tag data-tag of the element
 * @param {function} fn callback function
 */
function _wccAttachListener(selector, fn) {
    const item = _wccFindElement(selector);
    item && item.addEventListener("click", fn);
}
function _wccClassRemove() {
    return _wccClassAction("remove", ...arguments);
}

function _wccClassToggle() {
    return _wccClassAction("toggle", ...arguments);
}

function _wccClassAction(action, selector, className, forParent = true) {
    const item = _wccFindElement(selector, forParent);
    return item && item.classList[action](className);
}

function _wccFindElement(selector, forParent) {
    let createdSelector = selector;
    switch (true) {
        case selector.startsWith("="):
            createdSelector = `[data-tag="${selector.substring(1)}"]`;
        default:
            break;
    }
    const element = document.querySelector(createdSelector);
    if (!element || (forParent && !element.parentElement)) return null;
    return forParent ? element.parentElement : element;
}
/**
 * Remove an element from the DOM.
 * 
 * @param {string} tag data-tag of the element.
 */
function _wccRemoveElement(tag) {
    const item = _wccGetElementByTag(tag);
    item && item.remove();
}

/**
 * Remove styles by it's id.
 */
function _wccRemoveStyles() {
    const item = document.getElementById('wcc-style-inline');
    item && item.remove();
}

/**
 * Generate a random string for logging purposes.
 * 
 * @param {integer} length Length of the string to be generated.
 * @returns 
 */
ref._wccRandomString = function (length, allChars = true) {
    const chars = `${allChars ? `0123456789` : ""
        }ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz`;
    const response = [];
    for (let i = 0; i < length; i++)
        response.push(chars[Math.floor(Math.random() * chars.length)]);
    if (!allChars) return response.join("");
    return btoa(response.join("")).replace(/\=+$/, "");
}

/**
 * Remove banner if necessary.
 */
function _wccRemoveBanner() {
    _wccHideBanner();
    if (_wccStore._bannerConfig[currentLaw].config.revisitConsent.status === true) {
        _wccShowRevisit();
    }
    if(_wccGetType() === 'popup') {
        //Remove the overlay when consent updated
        _wccHideOverLay();
        //Remove wcc-popup-overflow class from <body>
        if (document.body && document.body.classList.contains('wcc-popup-overflow')) {
            document.body.classList.remove('wcc-popup-overflow');
        }
    }
}

/**
 * Initialize the plugin front-end operations.
 * 
 * @returns {boolean}
 */
async function _wccInitOperations() {
    await _wccSetBanner();
    _wccAttachNoticeStyles();
    _wccAttachShortCodeStyles();
    _wccRenderBanner();
    _wccSetShowMoreLess();
    // Determine consent renewed time
    let renew_date = _wccStore._renewConsent;
    // Update the consent time based on the last modified time of "wt_consent" cookie
    const consent_time = _wccGetCookieLastModified("wt_consent");
    // Check whether consent renewed date greater than current time
    if (!ref._wccGetFromStore("action") || _wccPreviewEnabled() || renew_date && renew_date > consent_time) {
        _wccShowBanner();
        _wccSetInitialState();
        if (renew_date && renew_date > consent_time) {
            _wccAcceptReject("reject");
            _wccRenewConsent();
        }
    } else {
        _wccRemoveBanner();
    }
}
function _wccPreviewEnabled() {
    let params = (new URL(document.location)).searchParams;
    return params.get("wcc_preview") && params.get("wcc_preview") === 'true';
}
/**
 * Sets up the cookie consent banner based on visitor's location and applicable privacy laws (GDPR/CCPA)
 */
async function _wccSetBanner() {
    const bannerConfig = _wccStore._bannerConfig;
    const availableLaws = Object.keys(bannerConfig);
   
    // Initialize variables
    let country = '';
    let is_eu = false;
    let region_code = '';
    // Get allowed regions for CCPA and GDPR.
    let ccpaAllowedRegions = _wccStore._ccpaAllowedRegions;
    let gdprAllowedRegions = _wccStore._gdprAllowedRegions;
    

    // Check if any law requires geolocation
    const needsGeolocation = availableLaws.some(law => 
        bannerConfig[law].settings.selectedRegion !== 'ALL'
    );
    
    // Only fetch visitor data if geolocation is needed
    if (needsGeolocation) {
        const visitor = await _wccGetCountryFromVisitorData();
        if (visitor) {
            country = visitor.country;
            is_eu = visitor.in_eu;
            region_code = visitor.region_code;
        }
    }

    if (availableLaws.length === 1) {
        currentLaw = availableLaws[0];
        let bannerEnabled = _wccBannerEnabled();
        if (!bannerEnabled) {
            showBanner = false;
        }
    } else {
        // Multiple laws - determine which one applies
        if (country === 'EU' || is_eu) {
            currentLaw = 'GDPR';
        } else if (country === 'US') {
            currentLaw = 'CCPA';
        } else {
            // Default to first available law if no specific conditions met
            currentLaw = availableLaws[0];
        }
    }

    let selectedRegion = _wccSelectedRegion();
    let bannerEnabled = _wccBannerEnabled();
    
    // Handle GDPR specific logic
    if (currentLaw === 'GDPR') {
        if (!bannerEnabled) {
            showBanner = false;
        } else if (selectedRegion !== 'ALL') {
            if (Array.isArray(gdprAllowedRegions) && gdprAllowedRegions.length > 0) {
                // Check if visitor's country is in allowed regions
                showBanner = gdprAllowedRegions.includes(country);
            } else {
                // Fallback to original logic if gdprAllowedRegions is empty
                showBanner = is_eu;
            }
        }
    } 
    // Handle CCPA specific logic
    else if (currentLaw === 'CCPA') {
        if (!bannerEnabled) {
            showBanner = false;
        } else if (selectedRegion !== 'ALL') {
            if (Array.isArray(ccpaAllowedRegions) && ccpaAllowedRegions.length > 0) {
                // Only proceed if visitor is from US
                if (country === 'US') {
                    // Check if visitor's region code is in allowed regions
                    showBanner = ccpaAllowedRegions.includes(region_code);
                } else {
                    showBanner = false;
                }
            } else {
                // Fallback to original logic if ccpaAllowedRegions is empty
                showBanner = _wccIsVisitorInCalifornia(country, region_code);
            }
        }
    }
}
/**
 * Sets the initial state of the plugin.
 */
function _wccSetInitialState() {
    const activeLaw = _wccGetLaw();
    ref._wccSetInStore("consent", "no");
    const ccpaCheckBoxValue = _wccFindCheckBoxValue();
    const responseCategories = { accepted: [], rejected: [] };

    for (const category of _wccStore._categories) {
        let valueToSet = "yes";

        if (showBanner) {
            if (
                (activeLaw === "gdpr" &&
                    !category.isNecessary &&
                    !category.defaultConsent.gdpr) ||
                (activeLaw === "ccpa" &&
                    ccpaCheckBoxValue &&
                    !category.defaultConsent.ccpa)
            ) {
                valueToSet = "no";
            }
        }

        if (valueToSet === "no") {
            responseCategories.rejected.push(category.slug);
        } else {
            responseCategories.accepted.push(category.slug);
        }

        ref._wccSetInStore(`${category.slug}`, valueToSet);
    }

    _wccUnblock();
    _wccSendConsentEvent(responseCategories);
}

/**
 * Add a class based on the banner type and position. Eg: 'wcc-banner-top'
 * 
 * @returns {boolean}
 */
function _wccAddPositionClass() {
    const notice = _wccGetElementByTag('notice');
    if (!notice) return false;
    const container = notice.closest('.wcc-consent-container');
    if (!container) return false;
    const type = _wccStore._bannerConfig[currentLaw].settings.type;
    let position = _wccStore._bannerConfig[currentLaw].settings.position;
    if (type === 'popup') {
        position = 'center';
        //Show overlay when popup visible
        _wccShowOverLay();
        //Add wcc-popup-overflow class to <body> to prevent scroll when layout type is popup
        document.body.classList.add('wcc-popup-overflow');
    }
    const noticeClass = 'wcc' + '-' + type + '-' + position;
    container.classList.add(noticeClass);
    const revisitConsent = _wccGetElementByTag('revisit-consent');
    if (!revisitConsent) return false;
    const revisitPosition = `wcc-revisit-${_wccStore._bannerConfig[currentLaw].config.revisitConsent.position}`;
    revisitConsent.classList.add(revisitPosition);
}

/**
 * Initialize the plugin operations.
 */
async function _wccInit() {
    try {
        _wccInitOperations();
        _wccRemoveAllDeadCookies();
        _wccWatchBannerElement();
    } catch (err) {
        console.error(err);
    }
}

/**
 * Domready event, alternative to jQuery(document).ready() function
 * 
 * @param {function} callback 
 * @returns 
 */
function _wccDomReady(callback) {
    if (typeof document === 'undefined') {
        return;
    }
    if (document.readyState === 'complete' || /** DOMContentLoaded + Images/Styles/etc loaded, so we call directly. */
        document.readyState === 'interactive' /** DOMContentLoaded fires at this point, so we call directly. */
    ) {
        return void callback();
    } /** DOMContentLoaded has not fired yet, delay callback until then. */
    document.addEventListener('DOMContentLoaded', callback);
}

/**
 * Callback function to Domready event.
 */
_wccDomReady(async function () {
    try {
        await _wccInit();
    } catch (err) {
        console.error(err);
    }
});

/**
 * Register event handler for all the action elements.
 */
function _wccRegisterListeners() {
    for (const { slug } of _wccStore._categories) {
        _wccAttachListener('detail-category-title', () =>
            document
                .getElementById(`wccCategory${slug}`)
                .classList.toggle("wcc-tab-active")
        );
    }
    _wccAttachListener("=settings-button", () => _wccSetPreferenceAction('settings-button'));
    _wccAttachListener("=detail-close", () => _wccHidePreferenceCenter());
    _wccAttachListener("=optout-cancel-button", () => _wccHidePreferenceCenter());
    _wccAttachListener("=close-button", () => _wccActionClose());
    _wccAttachListener("=donotsell-button", () => _wccSetPreferenceAction('donotsell-button'));
    _wccAttachListener("=reject-button", _wccAcceptReject("reject"));
    _wccAttachListener("=accept-button", _wccAcceptReject("all"));
    _wccAttachListener("=detail-accept-button", _wccAcceptReject("all"));
    _wccAttachListener("=detail-save-button", _wccAcceptReject());
    _wccAttachListener("=detail-category-preview-save-button", _wccAcceptReject());
    _wccAttachListener("=optout-confirm-button", _wccAcceptReject());
    _wccAttachListener("=detail-reject-button", _wccAcceptReject("reject"));
    _wccAttachListener("=revisit-consent", () => _revisitWccConsent());
    _wccAttachListener("=optout-close", () => _wccHidePreferenceCenter());
    _wccAttachListener("=category-tab", () => _wccShowTab('wccIABSectionCookie'));
    _wccAttachListener("=purpose-tab", () => _wccShowTab('wccIABSectionPurpose'));
    _wccAttachListener("=vendor-tab", () => _wccShowTab('wccIABSectionVendor'));
    _wccAttachListener('#wcc-iab-notice-toggle', () => _wccShowPreferenceCenter());
    _wccInitiAccordionTabs();
    _wccInitPreferenceButton();
    _wccAttachCategoryListeners();

}
function _wccAttachCategoryListeners() {
    if (!_wccStore._bannerConfig[currentLaw].config.auditTable.status) return;

    const categoryNames = _wccStore._categories.map(({ slug }) => slug);

    categoryNames.map((category) => {
        const selector = `#wccDetailCategory${category}`;
        _wccAttachListener(selector, ({ target: { id } }) => {
            // Don't toggle accordion if clicking the switch
            if (id === `wccSwitch${category}`) return;
            
            const accordion = document.querySelector(selector);
            const body = accordion.querySelector('.wcc-accordion-body');

            // Toggle accordion state
            const isActive = accordion.classList.toggle('wcc-accordion-active');
            
            // Update ARIA attributes
            accordion.setAttribute('aria-expanded', isActive);
            if (body) body.setAttribute('aria-hidden', !isActive);

            // Close other accordions (from original code)
            categoryNames
                .filter((categoryName) => categoryName !== category)
                .map((filteredName) => {
                    const otherAccordion = document.querySelector(`#wccDetailCategory${filteredName}`);
                    const otherBody = otherAccordion.querySelector('.wcc-accordion-body');
                    otherAccordion.classList.remove('wcc-accordion-active');
                    otherAccordion.setAttribute('aria-expanded', 'false');
                    if (otherBody) otherBody.setAttribute('aria-hidden', 'true');
                });
        });
    });
}
/**
 * Add support for accordion tabs on the privacy overview screen.
 */
function _wccInitiAccordionTabs() {
    _wccIabInnerAccordionClickListener('wccIABSectionPurpose');
    _wccIabInnerAccordionClickListener('wccIABSectionVendor');

    document.querySelectorAll(".wcc-child-accordion .wcc-child-accordion-item").forEach((item) => (
        item.addEventListener('click', function (event) {
            if (event.target.type === 'checkbox') return;

            const accordion = this.parentNode; // Get the parent accordion element
            const body = accordion.querySelector('.wcc-child-accordion-body'); // Find the body element

            const isActive = accordion.classList.toggle('wcc-child-accordion-active');

            // Update aria-expanded on the parent accordion
            accordion.setAttribute('aria-expanded', isActive ? 'true' : 'false');

            // Update aria-hidden on the body
            if (body) {
                body.setAttribute('aria-hidden', isActive ? 'false' : 'true');
            }
        })
    ));

    // Enable / disable all purposes/features consent based on user action
    const checkboxes = document.querySelectorAll('.wcc-consents-checkbox');
    checkboxes.forEach(function (checkbox) {
        checkbox.addEventListener('change', wcc_enable_disable_consent);
    });
}

/**
 * This function selects all elements with the class 'wcc-preference-btn', assigns a unique ID to each button,
 * and adds a click event listener that triggers the `_revisitWccConsent` function.
 * 
 */
function _wccInitPreferenceButton() {
    const preferenceButtons = document.querySelectorAll('.wcc-preference-btn'); // Select all buttons with the class
    preferenceButtons.forEach((button) => {
        // Generate a unique ID for each preference button
        const uniqueID = ref._wccRandomString(8, false);
        // Set the unique ID
        button.id = uniqueID;
        // Add an event listener for each button
        button.addEventListener('click', function () {
            _revisitWccConsent();
        });
    });
}

function wcc_enable_disable_consent() {
    let el = this.getAttribute('data-tag');
    const nestedInputs = document.querySelectorAll('.wcc-' + el + '-checkbox, .wcc-' + el + '-legitimate-interests-checkbox');
    const isChecked = this.checked;
    nestedInputs.forEach(input => {
        input.checked = isChecked;
    });
}
function _wccIabInnerAccordionClickListener(containerId) {
    const accordionItems = document.querySelectorAll(`#${containerId} .wcc-accordion .wcc-accordion-iab-item`);
    accordionItems.forEach((item) => {
        item.addEventListener('click', function (event) {
            if (event.target.type === 'checkbox') return;
            this.parentNode.classList.toggle('wcc-accordion-active');
            this.parentNode.setAttribute('aria-expanded', 'true');
            const accordion = this.parentNode; // Get the parent accordion element
            const body = accordion.querySelector('.wcc-accordion-body'); // Find the body element
            // Check if this accordion is being expanded or collapsed
            const isActive = accordion.classList.toggle('wcc-child-accordion-active');
            // Update aria-expanded on the parent accordion
            accordion.setAttribute('aria-expanded', isActive ? 'true' : 'false');
            // Update aria-hidden on the body
            if (body) {
                body.setAttribute('aria-hidden', isActive ? 'false' : 'true');
            }
        });
    });
}

function _wccToggleBanner(force = false) {
    const notice = _wccGetElementByTag('notice');
    const container = notice && notice.closest('.wcc-consent-container') || false;
    if (container) {
        force === true ? container.classList.add('wcc-hide') : container.classList.toggle('wcc-hide');
    }
}

function _wccToggleRevisit(force = false) {
    const revisit = _wccGetRevisit();
    if (revisit) {
        force === true ? _wccRevisitHide() : revisit.classList.toggle('wcc-revisit-hide');
    }
}
function _wccGetLaw() {
    return _wccStore._bannerConfig[currentLaw].settings.applicableLaw;
}
function _wccSelectedRegion() {
    return _wccStore._bannerConfig[currentLaw].settings.selectedRegion;
}
function _wccBannerEnabled() {
    return _wccStore._bannerConfig[currentLaw].settings.bannerEnabled;
}
function _wccPoweredByEnabled() {
    return _wccStore._bannerConfig[currentLaw].settings.poweredBy;
}
function _wccGetType() {
    return _wccStore._bannerConfig[currentLaw].settings.type;
}
function _wccGetBanner() {
    const notice = _wccGetElementByTag('notice');
    const container = notice && notice.closest('.wcc-consent-container') || false;
    return container && container || false;
}
function _wccHideBanner() {
    const notice = _wccGetBanner();
    notice && notice.classList.add('wcc-hide');
}
function _wccShowBanner() {
    const notice = _wccGetBanner();
    notice && notice.classList.remove('wcc-hide');
}
function _wccHideOverLay() {
    const overlay = document.querySelector('.wcc-overlay');
    overlay && overlay.classList.add('wcc-hide');
}
function _wccShowOverLay() {
    const overlay = document.querySelector('.wcc-overlay');
    overlay && overlay.classList.remove('wcc-hide');
}
function _wccToggleOverLay() {
    const overlay = document.querySelector('.wcc-overlay');
    overlay && overlay.classList.toggle('wcc-hide');
}
function _wccGetPreferenceCenter() {
    if (_wccGetType() === 'classic') {
        return _wccGetBanner();
    }
    let element = _wccGetLaw() === 'ccpa' ? _wccGetElementByTag("optout-popup") : _wccGetElementByTag("detail");
    return element && element.closest('.wcc-modal') || false;
}
function _wccHidePreferenceCenter() {
    const element = _wccGetPreferenceCenter();
    element && element.classList.remove(_wccGetPreferenceClass());
    if (_wccGetType() !== 'classic') {
        _wccHideOverLay();
        if (!ref._wccGetFromStore("action")) _wccShowBanner();
    }
    if (ref._wccGetFromStore("action")) _wccShowRevisit();
    const origin = _wccStore._preferenceOriginTag;
    origin && _wccSetFocus(origin)
}
function _wccShowPreferenceCenter() {
    const element = _wccGetPreferenceCenter();
    element && element.classList.add(_wccGetPreferenceClass());
    if (_wccGetType() !== 'classic') {
        _wccShowOverLay();
        _wccHideBanner();
    }
}
function _wccTogglePreferenceCenter() {
    const element = _wccGetPreferenceCenter();
    element && element.classList.toggle(_wccGetPreferenceClass());
    if (_wccGetType() !== 'classic') _wccToggleOverLay();
}
function _wccGetPreferenceClass() {
    return _wccGetType() === 'classic' ? 'wcc-consent-bar-expand' : 'wcc-modal-open';
}
function _wccGetRevisit() {
    const revisit = _wccGetElementByTag('revisit-consent');
    return revisit && revisit || false;
}
function _wccHideRevisit() {
    const revisit = _wccGetRevisit();
    revisit && revisit.classList.add('wcc-revisit-hide')
}
function _wccShowRevisit() {
    const revisit = _wccGetRevisit();
    revisit && revisit.classList.remove('wcc-revisit-hide')
}
function _wccSetPreferenceAction(tagName = false) {
    _wccStore._preferenceOriginTag = tagName;
    if (_wccGetType() === 'classic') {
        _wccTogglePreferenceCenter();
    } else {
        _wccShowPreferenceCenter();
    }
}
// Define section names array
const sectionNames = ['wccIABSectionCookie', 'wccIABSectionPurpose', 'wccIABSectionVendor'];
function _wccShowTab(tagName = false) {
    sectionNames.forEach(validTagName => {
        _wccNavBar();
        const tab = _wccGetTab(validTagName);
        if (validTagName === tagName) {
            tab && tab.classList.remove('wcc-hide');
        } else {
            tab && tab.classList.add('wcc-hide');
        }
    });
}
function _wccNavBar() {
    // Get all buttons
    const buttons = document.querySelectorAll('.wcc-iab-nav-item');

    // Add click event listeners to each button
    buttons.forEach(button => {
        button.addEventListener('click', function () {
            // Remove 'wcc-iab-nav-item-active' from all buttons
            buttons.forEach(btn => btn.classList.remove('wcc-iab-nav-item-active'));

            // Add 'wcc-iab-nav-item-active' only to the clicked button
            this.classList.add('wcc-iab-nav-item-active');
        });
    });
}
function _wccGetTab(tagName = false) {
    const tab = _wccGetElementByTag(tagName);
    return tab && tab || false;
}
/**
 * Replace footer shadow with current preference center background.
 * 
 * @param {object} $doc Dom node.
 * @returns 
 */
function _wccSetFooterShadow($doc) {
    const footer = $doc.querySelector('[data-tag="detail"] .wcc-footer-shadow');
    const preference = $doc.querySelector('[data-tag="detail"]');
    if (!footer) return;
    const background = preference && preference.style.backgroundColor || '#ffffff';
    footer.style.background = `linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, ${background
        } 100%)`;
}

/**
 * Remove all the rejected cookies.
 * 
 * @param {object} cookies Cookies list.
 */
function _wccRemoveDeadCookies({ cookies }) {
    const currentCookieMap = ref._wccGetCookieMap();
    for (const { cookieID, domain } of cookies) {
        for (const existingCookieID in currentCookieMap) {
            // Check if the cookieID matches exactly or if it matches a wildcard pattern
            const isMatch = 
                existingCookieID === cookieID || 
                (cookieID.includes('*') && new RegExp(`^${cookieID.replace('*', '.*')}$`).test(existingCookieID));
            
            if (isMatch) {
                [domain, ""].map((cookieDomain) =>
                    ref._wccSetCookie(existingCookieID, "", 0, cookieDomain)
                );
            }
        }
    }
}
function _wccSetPreferenceCheckBoxStates(revisit = false) {
    for (const category of _wccStore._categories) {
        const cookieValue = ref._wccGetFromStore(category.slug);
        const checked =
            cookieValue === "yes" ||
            (!cookieValue &&
                category.defaultConsent[_wccGetLaw()]) || category.isNecessary;

        const disabled = category.isNecessary;
        const shortCodeData = _wccStore._bannerConfig[currentLaw].settings.shortcodes.find(
            (code) => code.key === 'wcc_category_toggle_label'
        );
        const toggleTextFormatted = shortCodeData.content.replace(
            `[wcc_preference_{{category_slug}}_title]`,
            category.name
        );
        _wccSetCheckboxes(
            category,
            checked,
            disabled,
            toggleTextFormatted,
            revisit
        );
        _wccSetPreferenceState(category);
    }
}

function _wccSetCheckboxes(
    category,
    checked,
    disabled,
    formattedLabel,
    revisit = false
) {
    const toggle = _wccStore._bannerConfig[currentLaw].config.preferenceCenter.toggle;
    const activeColor = toggle.states.active.styles['background-color'];
    const inactiveColor = toggle.states.inactive.styles['background-color'];

    [`wccCategoryDirect`, `wccSwitch`].map((key) => {
        const boxElem = document.getElementById(`${key}${category.slug}`);
        if (!boxElem) return;
        _wccSetCategoryToggle(
            boxElem,
            category,
            revisit);
        boxElem.checked = checked;
        boxElem.disabled = disabled;
        boxElem.style.backgroundColor = checked ? activeColor : inactiveColor;
        _wccSetCheckBoxAriaLabel(boxElem, checked, formattedLabel);
        if (revisit) return;
        boxElem.addEventListener("change", ({ currentTarget: elem }) => {
            const isChecked = elem.checked;
            elem.style.backgroundColor = isChecked ? activeColor : inactiveColor;
            _wccSetCheckBoxAriaLabel(boxElem, isChecked, formattedLabel);
        });
    });
}
function _wccSetCategoryToggle(element, category = {}, revisit = false) {
    if (revisit) return;
    if (element.parentElement.getAttribute('data-tag') === 'detail-category-toggle') {
        _wccSetCategoryPreferenceToggle(element, category);
    } else if (element.parentElement.getAttribute('data-tag') === 'detail-category-preview-toggle') {
        _wccSetCategoryPreview(element, category);
    }

}
function _wccSetCategoryPreferenceToggle(element, category) {
    let toggleContainer = element.closest('.wcc-accordion-item');
    if (!toggleContainer) return;
    const toggleSwitch = toggleContainer.querySelector('.wcc-switch');
    const necessaryText = toggleContainer.querySelector('.wcc-always-active');
    if (category.isNecessary) {
        toggleSwitch && toggleSwitch.remove();
    } else {
        necessaryText && necessaryText.remove();
        if (_wccGetType() === 'classic' && _wccStore._bannerConfig[currentLaw].config.categoryPreview.status || (category.cookies && category.cookies.length === 0) && !category.foundNoCookieScript) {
            toggleSwitch && toggleSwitch.remove();
        }
    }
}
function _wccSetPreferenceState(category) {
    if (_wccStore._bannerConfig[currentLaw].config.auditTable.status === false) {
        const tableElement = document.querySelector(
            `#wccDetailCategory${category.slug} [data-tag="audit-table"]`
        );
        tableElement && tableElement.remove();
        const chevronElement = document.querySelector(
            `#wccDetailCategory${category.slug} .wcc-accordion-chevron`
        );
        chevronElement && chevronElement.classList.add("wcc-accordion-chevron-hide");
    }
}
function _wccSetCategoryPreview(element, category) {
    if ((category.cookies && category.cookies.length === 0) && !category.isNecessary)
        element.parentElement.parentElement.remove();
}

function _wccSetCheckBoxAriaLabel(boxElem, isChecked, formattedLabel, isCCPA = false) {

    if (!boxElem) return;
    const keyName = isChecked ? "disable" : "enable";
    const textCode = `wcc_${keyName}_${isCCPA ? "optout" : "category"}_label`;
    const shortCodeData = _wccStore._bannerConfig[currentLaw].settings.shortcodes.find(
        (code) => code.key === textCode
    );
    if (!shortCodeData) return;
    const labelText = formattedLabel
        .replace(/{{status}}/g, keyName)
        .replace(`[${textCode}]`, shortCodeData.content);
    boxElem.setAttribute("aria-label", labelText);
}
/**
 * Render banner after processing.
 */
async function _wccRenderBanner() {
    const myEvent = new CustomEvent("_wccBannerVisible", {
        detail: {
            bannerVisibility: showBanner, // Include showBanner in the detail property
            currentLaw: currentLaw,
        },
        bubbles: true,
        cancelable: true,
        composed: false,
    });
    // Ensure the event listener is added before dispatching the event
    setTimeout(() => {
        document.body.dispatchEvent(myEvent);
    }, 0);

    if (currentLaw && showBanner) {
        const template = document.getElementById(`wccBannerTemplate_${currentLaw}`);
        if (template) {
            const templateHtml = template.innerHTML;
            const doc = new DOMParser().parseFromString(templateHtml, 'text/html');
            _wccSetFooterShadow(doc);
            document.body.insertAdjacentHTML(
                "afterbegin",
                doc.body.innerHTML
            );
        }
    }
    _wccSetPreferenceCheckBoxStates();
    _wccRegisterListeners();
    _wccSetCCPAOptions();
    _wccSetPlaceHolder();
    _wccAttachReadMore();
    _wccRemoveStyles();
    _wccAddPositionClass();
    _wccAddRtlClass();
    _wccSetPoweredBy();
}

async function _wccGetCountryFromVisitorData() {
    const apiUrl = _wccStore._restApiUrl;
    const response = await fetch(apiUrl);
    const data = await response.json();
    return data;
}

/**
 * Check whether the visitor country is US and If _restrictToCA is true check the region code also.
 * @since 3.0.2
 * @returns boolean
 */
function _wccIsVisitorInCalifornia(country, region_code) {
    const _restricttocalifornia = _wccStore._restrictToCA;
    // Check if restriction to California is enabled
    if (_restricttocalifornia) {
        // Restrict to California only
        return country === 'US' && region_code === 'CA';
    } else {
        // Only check if country is US
        return country === 'US';
    }
}

/**
 * Accept or reject the consent based on the option.
 * 
 * @param {string} option Type of consent. 
 * @returns {void}
 */
function _wccAcceptReject(option = "custom") {
    return () => {
        _wccAcceptCookies(option);
        _wccSetConsentID();
        _wccSetConsentTime();
        _wccRemoveBanner();
        _wccHidePreferenceCenter();
        _wccLogConsent();
        _wccAfterConsent();
    };
}

function _wccActionClose() {
    const actionType = _wccStore._closeButtonAction;
    _wccAcceptReject(actionType)();
}
/**
 * Consent accept callback.
 * 
 * @param {string} choice  Type of consent.
 */
function _wccAcceptCookies(choice = "all") {
    const activeLaw = _wccGetLaw();
    const ccpaCheckBoxValue = _wccFindCheckBoxValue();

    ref._wccSetInStore("action", "yes");
    if (activeLaw === 'gdpr') {
        ref._wccSetInStore("consent", choice === "reject" ? "no" : "yes");
    } else {
        ref._wccSetInStore("consent", ccpaCheckBoxValue ? "yes" : "no");
    }
    const responseCategories = { accepted: [], rejected: [] };
    for (const category of _wccStore._categories) {
        let valueToSet = "no";
        if (activeLaw === 'gdpr') {
            valueToSet =
                !category.isNecessary &&
                    (choice === "reject" ||
                        (choice === "custom" && !_wccFindCheckBoxValue(category.slug)))
                    ? "no"
                    : "yes";
        } else {
            valueToSet = (ccpaCheckBoxValue && !category.defaultConsent.ccpa) || (!category.isNecessary && currentLaw === 'CCPA' && choice === "reject") ? "no" : "yes";
        }
        ref._wccSetInStore(`${category.slug}`, valueToSet);
        if (valueToSet === "no") {
            responseCategories.rejected.push(category.slug);
            _wccRemoveDeadCookies(category);
        } else responseCategories.accepted.push(category.slug);
    }
    let customEventSupport = _wccStore._customEvents;
    // Add GTM event trigger after consent mode flags are set
    if (window.dataLayer && customEventSupport) {
        window.dataLayer.push({
            "event": "cookie_consent_updated"
        });
    }
    _wccUnblock();
    _wccSendConsentEvent(responseCategories,choice);
}
function _wccSetShowMoreLess() {
    const activeLaw = _wccGetLaw();
    const showCode = _wccStore._bannerConfig[currentLaw].settings.shortcodes.find(
        (code) => code.key === "wcc_show_desc"
    );
    const hideCode = _wccStore._bannerConfig[currentLaw].settings.shortcodes.find(
        (code) => code.key === "wcc_hide_desc"
    );

    if (!showCode || !hideCode) return;
    const hideButtonContent = hideCode.content;
    const showButtonContent = showCode.content;

    const contentLimit = window.innerWidth < 376 ? 150 : 300;
    const element = document.querySelector(
        `[data-tag="${activeLaw === "gdpr" ? "detail" : "optout"}-description"]`
    );
    if (!element) return;
    const content = element.textContent;
    if (content.length < contentLimit) return;
    const contentHTML = element.innerHTML;
    const htmlDoc = new DOMParser().parseFromString(contentHTML, "text/html");
    const innerElements = htmlDoc.querySelectorAll("body > p");
    if (innerElements.length <= 1) return;
    let strippedContent = ``;
    for (let index = 0; index < innerElements.length; index++) {
        if (index === innerElements.length - 1) return;
        const element = innerElements[index];
        if (`${strippedContent}${element.outerHTML}`.length > contentLimit)
            element.insertAdjacentHTML("beforeend", `...&nbsp;${showButtonContent}`);
        strippedContent = `${strippedContent}${element.outerHTML}`;
        if (strippedContent.length > contentLimit) break;
    }
    function showMoreHandler() {
        element.innerHTML = `${contentHTML}${hideButtonContent}`;
        _wccAttachListener("=hide-desc-button", showLessHandler);
    }
    function showLessHandler() {
        element.innerHTML = strippedContent;
        _wccAttachListener("=show-desc-button", showMoreHandler);
    }
    showLessHandler();
}
/**
 * Toggle show more or less on click event.
 * 
 * @param {object} object Object containing toggle buttons and texts.
 * @param {*} element Target element.
 */
function _wccToggleMoreLess(object, element) {
    let {
        currentTarget,
        target
    } = element;
    if (target && target.tagName.toUpperCase() !== 'BUTTON') return;
    const ariaExpanded = currentTarget.getAttribute('aria-expanded');
    const trimmed = ariaExpanded === 'false';
    let btn = object.btnTrim;
    let text = object.originalText;
    if (!trimmed) {
        btn = object.btnExpand;
        text = object.truncatedText;
    }
    currentTarget.innerHTML = `${text}${btn}`;
    currentTarget.ariaExpanded = trimmed;
}

/**
 * Add styles to the shortcode HTML rendered outside of the banner.
 * 
 * @returns {void}
 */
function _wccAttachShortCodeStyles() {
    const shortCodes = _wccStore._tags;
    Array.prototype.forEach.call(shortCodes, function (shortcode) {
        document.querySelectorAll('[data-tag=' + shortcode.tag + ']').forEach(function (item) {
            let styles = '';
            for (const key in shortcode.styles) {
                styles += `${key}: ${shortcode.styles[key]};`;
            }
            item.style.cssText = styles;
        });
    });
}

/** Script blocker Version 2 */

const _wccCreateElementBackup = document.createElement;
document.createElement = (...args) => {
    const createdElement = _wccCreateElementBackup.call(document, ...args);
    if (createdElement.nodeName.toLowerCase() !== "script") return createdElement;
    const originalSetAttribute = createdElement.setAttribute.bind(createdElement);
    Object.defineProperties(createdElement, {
        src: {
            get: function () {
                return createdElement.getAttribute("src");
            },
            set: function (value) {
                if (_wccShouldChangeType(createdElement, value))
                    originalSetAttribute("type", "javascript/blocked");
                originalSetAttribute("src", value);
                return true;
            },
        },
        type: {
            get: function () {
                return createdElement.getAttribute("type");
            },
            set: function (value) {
                value = _wccShouldChangeType(createdElement)
                    ? "javascript/blocked"
                    : value;
                originalSetAttribute("type", value);
                return true;
            },
        },
    });
    createdElement.setAttribute = (name, value) => {
        if (name === "type" || name === "src")
            return (createdElement[name] = value);
        originalSetAttribute(name, value);
        if (name === "data-wcc" && !_wccShouldChangeType(createdElement))
            originalSetAttribute("type", "text/javascript");
    };
    return createdElement;
};

function _wccMutationObserver(mutations) {
    const urlParams = new URLSearchParams(window.location.search);
    if (urlParams.has('wcc_bypass')) return;

    for (const { addedNodes } of mutations) {
        for (const node of addedNodes) {
            try {
                // Handle TikTok blockquote elements.
                if (node.nodeName === 'BLOCKQUOTE' && node.classList.contains('tiktok-embed')) {
                    const videoId = node.getAttribute('data-video-id');
                    if (!videoId) continue;

                    const uniqueID = ref._wccRandomString(8, false);
                    const pseudoIframe = {
                        nodeName: 'iframe',
                        src: `https://www.tiktok.com/embed/${videoId}`,
                        offsetWidth: parseInt(node.style.maxWidth) || 605,
                        offsetHeight: parseInt(node.style.minHeight) || 700,
                        insertAdjacentHTML: function (position, html) {
                            node.insertAdjacentHTML(position, html);
                        }
                    };

                    const cleanedHostname = _wccCleanHostName('tiktok.com');
                    _wccAddProviderToList(node, cleanedHostname);
                    
                    // Check if element has data-wcc attribute that should prevent blocking.
                    if (node.hasAttribute('data-wcc') && !_wccIsCategoryToBeBlocked(node.getAttribute('data-wcc'))) {
                        continue;
                    }
                    
                    // Check if provider should be blocked.
                    if (!_wccShouldBlockProvider(cleanedHostname)) continue;

                    const category = _wccGetCategoryFromBlockedScript(node, cleanedHostname);
                    _wccAddPlaceholder(pseudoIframe, uniqueID, category);

                    const tiktokScript = document.querySelector('script[src*="tiktok.com/embed.js"]');
                    if (tiktokScript) tiktokScript.remove();

                    node.remove();
                    _wccStore._backupNodes.push({
                        position: 'body',
                        node: node.cloneNode(true),
                        uniqueID
                    });
                    continue;
                }

                //Handle Elementor video widget (YouTube, Vimeo, Dailymotion, VideoPress, Self Hosted).
                if (node.nodeType === 1 && node.classList.contains('elementor-video')) {
                    const widgetContainer = node.closest('.elementor-widget-video');
                    if (!widgetContainer) continue;

                    const settings = widgetContainer.getAttribute('data-settings');
                    if (!settings) continue;

                    try {
                        const parsed = JSON.parse(settings.replace(/&quot;/g, '"'));
                        const videoType = parsed.video_type || 'youtube';
                        
                        let videoUrl = '';
                        let hostname = '';
                        let videoId = '';
                        let embedUrl = '';
                        let externalUrlEnabled = false;
                        
                        // Handle different video types.
                        switch (videoType) {
                            case 'youtube':
                                videoUrl = parsed.youtube_url;
                                if (!videoUrl || typeof videoUrl !== 'string') continue;
                                const ytMatch = videoUrl.match(/(?:youtu\.be\/|youtube\.com\/(?:watch\?v=|embed\/))([\w-]{11})/);
                                if (!ytMatch) continue;
                                videoId = ytMatch[1];
                                hostname = 'youtube.com';
                                embedUrl = `https://www.youtube.com/embed/${videoId}`;
                                break;
                                
                            case 'vimeo':
                                videoUrl = parsed.vimeo_url;
                                if (!videoUrl || typeof videoUrl !== 'string') continue;
                                const vimeoMatch = videoUrl.match(/(?:vimeo\.com\/)(\d+)/);
                                if (!vimeoMatch) continue;
                                videoId = vimeoMatch[1];
                                hostname = 'vimeo.com';
                                embedUrl = `https://player.vimeo.com/video/${videoId}`;
                                break;
                                
                            case 'dailymotion':
                                videoUrl = parsed.dailymotion_url;
                                if (!videoUrl || typeof videoUrl !== 'string') continue;
                                const dmMatch = videoUrl.match(/(?:dailymotion\.com\/video\/)([a-zA-Z0-9]+)/);
                                if (!dmMatch) continue;
                                videoId = dmMatch[1];
                                hostname = 'dailymotion.com';
                                embedUrl = `https://www.dailymotion.com/embed/video/${videoId}`;
                                break;
                                
                            case 'videopress':
                                videoUrl = parsed.videopress_url;
                                if (!videoUrl || typeof videoUrl !== 'string') continue;
                                const vpMatch = videoUrl.match(/(?:videopress\.com\/v\/)([a-zA-Z0-9]+)/);
                                if (!vpMatch) continue;
                                videoId = vpMatch[1];
                                hostname = 'videopress.com';
                                embedUrl = `https://videopress.com/embed/${videoId}`;
                                break;
                                
                            case 'hosted':
                                // Self-hosted videos - check if they should be blocked.
                                const externalUrl = parsed.external_url;
                                externalUrlEnabled = parsed.external_url_enabled === 'yes';
                                
                                if (externalUrlEnabled && externalUrl && typeof externalUrl === 'string') {
                                    // External URL is enabled and provided - treat as third-party content.
                                    try {
                                        const url = new URL(externalUrl);
                                        hostname = url.hostname;
                                        embedUrl = externalUrl;
                                    } catch (urlError) {
                                        // If external URL is invalid, skip this video.
                                        continue;
                                    }
                                } else {
                                    // External URL is disabled or not provided - this is a WordPress media file.
                                    // For self-hosted videos, we should block them by default unless they have data-wcc="necessary".
                                    const videoSrc = node.src || node.getAttribute('src');
                                    if (videoSrc && typeof videoSrc === 'string') {
                                        try {
                                            const url = new URL(videoSrc);
											

                                            // Block self-hosted videos unless they're marked as necessary.
                                            // Check if the video element has data-wcc attribute.
                                            if (node.hasAttribute('data-wcc') && node.getAttribute('data-wcc') === 'necessary') {
                                                // Video is marked as necessary - skip blocking.
                                                continue;
                                            }
                                            // Block the video and use the full path for more specific blocking.
                                            hostname = `${url.hostname}${url.pathname}`;
                                            embedUrl = videoSrc;
                                            

                                        } catch (urlError) {
                                            // If video src is invalid, skip this video.
                                            continue;
                                        }
                                    } else {
                                        // No video src found - skip blocking.
                                        continue;
                                    }
                                }
                                break;
                                
                            default:
                                // Unknown video source, skip.
                                continue;
                        }
                        
                        // Skip if no valid video configuration found
                        if (!embedUrl || !hostname) continue;

                        const uniqueID = ref._wccRandomString(8, false);

                        // Real iframe for restoring after consent.
                        const realIframe = document.createElement('iframe');
                        realIframe.src = embedUrl;
                        realIframe.width = widgetContainer.offsetWidth || 560;
                        realIframe.height = widgetContainer.offsetHeight || 315;
                        realIframe.frameBorder = 0;
                        
                        // Set appropriate allow attributes based on video source.
                        if (hostname === 'youtube.com') {
                            realIframe.setAttribute("allow", "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture");
                        } else if (hostname === 'vimeo.com') {
                            realIframe.setAttribute("allow", "autoplay; fullscreen; picture-in-picture");
                        } else {
                            realIframe.setAttribute("allow", "autoplay; fullscreen");
                        }

                        // Pseudo iframe for placeholder.
                        const pseudoIframe = {
                            nodeName: 'iframe',
                            src: realIframe.src,
                            offsetWidth: realIframe.width,
                            offsetHeight: realIframe.height,
                            insertAdjacentHTML: function (position, html) {
                                node.insertAdjacentHTML(position, html);
                            }
                        };

                        const cleanedHostname = _wccCleanHostName(hostname);
                        _wccAddProviderToList(node, cleanedHostname);
                        
                        // Check if element has data-wcc attribute that should prevent blocking.
                        if (node.hasAttribute('data-wcc') && !_wccIsCategoryToBeBlocked(node.getAttribute('data-wcc'))) {
                            continue;
                        }
                        // Check if provider should be blocked.
                        if (!_wccShouldBlockProvider(cleanedHostname)) continue;

                        const category = _wccGetCategoryFromBlockedScript(node, cleanedHostname);
                        _wccAddPlaceholder(pseudoIframe, uniqueID, category);

                        // For self-hosted videos, store the original video element, not the iframe.
                        const backupNode = (videoType === 'hosted' && !externalUrlEnabled) ? 
                            node.cloneNode(true) : // Store original video element for self-hosted.
                            realIframe.cloneNode(true); // Store iframe for external videos.
                        
                        node.remove();
                        _wccStore._backupNodes.push({
                            position: 'body',
                            node: backupNode,
                            uniqueID
                        });
                    } catch (e) {
                        console.error('Error processing Elementor video:', e);
                    }

                    continue;
                }

                // Original script/iframe blocking.
                if (!node.src || !node.nodeName || !["script", "iframe"].includes(node.nodeName.toLowerCase()))
                    continue;

                try {
                    let urlToParse = node.src;
                    let hostname, pathname;


                    if (urlToParse.match(/^\/[a-zA-Z0-9]+\/?$/)) {
                        hostname = window.location.hostname;
                        pathname = urlToParse;
                    } else {
                        try {
                            const url = new URL(
                                urlToParse.startsWith("//") 
                                    ? `${window.location.protocol}${urlToParse}`
                                    : urlToParse.startsWith("/")
                                        ? `${window.location.origin}${urlToParse}`
                                        : urlToParse.match(/^https?:\/\//)
                                            ? urlToParse
                                            : `${window.location.origin}/${urlToParse}`
                            );
                            hostname = url.hostname;
                            pathname = url.pathname;
                        } catch (urlError) {
                            hostname = window.location.hostname;
                            pathname = urlToParse.startsWith('/') ? urlToParse : `/${urlToParse}`;
                        }
                    }

                    const cleanedHostname = _wccCleanHostName(`${hostname}${pathname}`);
                    _wccAddProviderToList(node, cleanedHostname);
                    
                    // Check if element has data-wcc attribute that should prevent blocking.
                    if (node.hasAttribute('data-wcc') && !_wccIsCategoryToBeBlocked(node.getAttribute('data-wcc'))) {
                        continue;
                    }
                    
                    // Check if provider should be blocked.
                    if (!_wccShouldBlockProvider(cleanedHostname)) continue;

                    const uniqueID = ref._wccRandomString(8, false);
                    if (node.nodeName.toLowerCase() === "iframe") {
                        const category = _wccGetCategoryFromBlockedScript(node, cleanedHostname);
                        _wccAddPlaceholder(node, uniqueID, category);
                    } else {
                        node.type = "javascript/blocked";
                        const scriptEventListener = function (event) {
                            event.preventDefault();
                            node.removeEventListener("beforescriptexecute", scriptEventListener);
                        };
                        node.addEventListener("beforescriptexecute", scriptEventListener);
                    }

                    const position = document.head.compareDocumentPosition(node) & 
                        Node.DOCUMENT_POSITION_CONTAINED_BY ? "head" : "body";

                    node.remove();
                    _wccStore._backupNodes.push({
                        position: position,
                        node: node.cloneNode(),
                        uniqueID
                    });
                } catch (error) {
                    console.log('Script processing error:', {
                        src: node.src,
                        nodeType: node.nodeName,
                        error: error.message
                    });
                    continue;
                }
            } catch (error) {
                console.error('Error in mutation observer:', error);
            }
        }
    }
}

function _wccUnblock() {
    if (navigator.doNotTrack === 1) return;

    const consent = ref._wccGetFromStore("consent");
    if (
        (_wccGetLaw() === "gdpr" &&
        (!consent || consent !== "yes") && showBanner)
    )
        return;

    _wccStore._backupNodes = _wccStore._backupNodes.filter(
        ({ position, node, uniqueID }) => {
            try {
                if (_wccShouldBlockProvider(node.src)) return true;

                const frame = document.getElementById(uniqueID);

                // Handle TikTok embeds
                const isTikTok = node.nodeName === 'BLOCKQUOTE' &&
                                 node.classList.contains('tiktok-embed');

                if (isTikTok && frame) {
                    frame.parentNode.insertBefore(node, frame);
                    const script = document.createElement('script');
                    script.src = 'https://www.tiktok.com/embed.js';
                    script.async = true;
                    document.body.appendChild(script);
                    frame.parentNode.removeChild(frame);
                    return false;
                }

                // Handle script-like nodes (including type="javascript/blocked")
                const isScriptLike = (
                    node.src &&
                    node.type &&
                    node.type.startsWith("javascript")
                );

                if (isScriptLike) {
                    const scriptNode = document.createElement("script");
                    scriptNode.src = node.src;
                    scriptNode.type = "text/javascript";
                    scriptNode.async = true;

                    const target = (position === "head") ? document.head : document.body;
                    target.appendChild(scriptNode);

                    if (frame) frame.parentNode.removeChild(frame);
                    return false;
                }

                // Handle iframe-based embeds if frame exists
                if (frame) {
                    // Check if this is a restored Elementor video iframe (has all the attributes we set)
                    if (node.frameBorder !== undefined && node.hasAttribute && node.hasAttribute('allow')) {
                        // This is an Elementor video iframe - restore it with all attributes
                        frame.parentNode.insertBefore(node, frame);
                        frame.parentNode.removeChild(frame);
                    } else if (node.nodeName === 'VIDEO') {
                        // This is a self-hosted video element - restore it directly
                        frame.parentNode.insertBefore(node, frame);
                        frame.parentNode.removeChild(frame);
                    } else {
                        // Generic iframe restoration
                        const iframe = document.createElement("iframe");
                        iframe.src = node.src;
                        iframe.width = frame.offsetWidth;
                        iframe.height = frame.offsetHeight;
                        frame.parentNode.insertBefore(iframe, frame);
                        frame.parentNode.removeChild(frame);
                    }
                }

                return false;
            } catch (error) {
                console.error(error);
                return false;
            }
        }
    );
}

function _wccClearListeners() {
    _nodeListObserver.disconnect();
    document.createElement = _wccCreateElementBackup;
}
function _wccAddProviderToList(node, cleanedHostname) {
    const categoryName =
        node.hasAttribute("data-wcc") && node.getAttribute("data-wcc");
    if (!categoryName) return;
    for (const category of _wccStore._categories)
        if (category.isNecessary && category.slug === categoryName && true === category.defaultConsent[currentLaw]) return;
    const provider = _wccStore._providersToBlock.find(
        ({ re }) => re === cleanedHostname
    );
    if (!provider)
        _wccStore._providersToBlock.push({
            re: cleanedHostname,
            categories: [categoryName],
            fullPath: false,
        });
    else if (!provider.isOverriden) {
        provider.categories = [categoryName];
        provider.isOverriden = true;
    } else if (!provider.categories.includes(categoryName))
        provider.categories.push(categoryName);
}

const _nodeListObserver = new MutationObserver(_wccMutationObserver);
_nodeListObserver.observe(document.documentElement, {
    childList: true,
    subtree: true,
});
function _wccCleanHostName(name) {
    return name.replace(/^www./, "");
}

function _wccIsCategoryToBeBlocked(category) {
    const cookieValue = ref._wccGetFromStore(category);
    const normalizedLaw = currentLaw.toLowerCase(); // Ensure case-insensitive key access
    return (
        cookieValue === "no" || 
        (!cookieValue &&
            _wccStore._categories.some(
                (cat) => cat.slug === category && !cat.isNecessary && !cat.defaultConsent[normalizedLaw]
            ))
    );
}

function _wccShouldBlockProvider(formattedRE) {
    const provider = _wccStore._providersToBlock.find(({ re }) =>
        new RegExp(_wccEscapeRegex(re)).test(formattedRE)
    );
    return (
        provider &&
        provider.categories.some((category) => _wccIsCategoryToBeBlocked(category))
    );
}

function _wccGetCategoryFromBlockedScript(element, cleanedHostname) {
    // Priority 1: Check data-wcc attribute
    if (element.hasAttribute && element.hasAttribute('data-wcc')) {
        const dataWcc = element.getAttribute('data-wcc');
        if (dataWcc && dataWcc !== 'necessary') {
            return [dataWcc]; // Return as array for consistency
        }
    }
    
    // Priority 2: Check provider pattern in _wccStore._providersToBlock
    if (cleanedHostname && _wccStore._providersToBlock) {
        const provider = _wccStore._providersToBlock.find(({ re }) =>
            new RegExp(_wccEscapeRegex(re)).test(cleanedHostname)
        );
        if (provider && provider.categories && provider.categories.length > 0) {
            // Return all categories that should be blocked, or all categories if none are blocked
            const blockedCategories = provider.categories.filter((category) => _wccIsCategoryToBeBlocked(category));
            return blockedCategories.length > 0 ? blockedCategories : provider.categories;
        }
    }
    
    // return null if no category is found
    return null;
}
function _wccShouldChangeType(element, src) {
    return (
        (element.hasAttribute("data-wcc") &&
            _wccIsCategoryToBeBlocked(
                element.getAttribute("data-wcc")
            )) ||
        _wccShouldBlockProvider(src ? src : element.src)
    );
}

/**
 * Add readmore button to consent notice.
 * 
 * @returns void
 */
function _wccAttachReadMore() {
    const readMoreButton = _wccStore._bannerConfig[currentLaw].settings.shortcodes.find(
        (code) => code.key === "wcc_readmore"
    );
    if (!readMoreButton.status) return;
    const content = readMoreButton.content;
    const styles = _wccStore._bannerConfig[currentLaw].config.readMore.styles;
    const readMoreElement = document.querySelector(
        '[data-tag="description"]'
    );
    if (!readMoreElement) return;
    if (readMoreElement.childNodes.length > 1) {
        const innerElement = document.querySelector(
            '[data-tag="description"] p:last-child'
        );
        innerElement && innerElement.insertAdjacentHTML(
            "beforeend",
            `&nbsp;${content}`
        );
    } else {
        readMoreElement.insertAdjacentHTML(
            "beforeend",
            `&nbsp;${content}`
        );
    }
    const placeHolders = document.querySelectorAll(
        `[data-tag="readmore-button"]`
    );
    if (placeHolders.length < 1) return;
    Array.from(placeHolders).forEach((placeHolder) => {
        for (const style in styles) {
            if (!styles[style]) continue;
            placeHolder.style[style] = styles[style];
        }
    });
}

function _wccAfterConsent() {
    if (_wccGetLaw() === 'gdpr') _wccSetPreferenceCheckBoxStates(true);

    if (_wccStore._bannerConfig[currentLaw].behaviours.reloadBannerOnAccept === true) {
        window.location.reload();
    }
}

function _wccSendConsentEvent(responseCategories, status = "initial") {
    const consentUpdate = new CustomEvent('wcc_consent_update', {
        detail: {
            status: status,
            categories: responseCategories,
            currentLaw: currentLaw
        },
    });
    document.dispatchEvent(consentUpdate);

    // Push consent data to dataLayer if it exists
    if (window.dataLayer) {
        window.dataLayer.push({
            "event": "wcc_cookie_consent_update",
            "cookie_consent_status": status,
            "cookie_consent_categories": responseCategories
        });
    }
}

function _wccAttachNoticeStyles() {
    if (document.getElementById("wcc-style") || !_wccStyle) return;
    document.head.insertAdjacentHTML(
        "beforeend",
        ` <style id="wcc-style">${_wccStyle.css[currentLaw]}</style>`
    );
}

function _wccFindCheckBoxValue(id = "") {
    const elemetsToCheck = id
        ? [`wccSwitch`, `wccCategoryDirect`]
        : [`wccCCPAOptOut`];
    return elemetsToCheck.some((key) => {
        const checkBox = document.getElementById(`${key}${id}`);
        return checkBox && checkBox.checked;
    });
}

function _wccAddPlaceholder(htmlElm, uniqueID, category = null) {
    const shortCodeData = _wccStore._bannerConfig[currentLaw].settings.shortcodes.find(
        (code) => code.key === 'wcc_video_placeholder'
    );
    const videoPlaceHolderDataCode = shortCodeData.content;
    const { offsetWidth, offsetHeight } = htmlElm;
    if (offsetWidth === 0 || offsetHeight === 0) return;
    
    htmlElm.insertAdjacentHTML
        ? htmlElm.insertAdjacentHTML("beforebegin", `${videoPlaceHolderDataCode}`.replace("[UNIQUEID]", uniqueID))
        : document.body.insertAdjacentHTML("beforeend", `${videoPlaceHolderDataCode}`.replace("[UNIQUEID]", uniqueID));

    const addedNode = document.getElementById(uniqueID);
    addedNode.style.width = `${offsetWidth}px`;
    addedNode.style.height = `${offsetHeight}px`;
    
    const innerTextElement = document.querySelector(
        `#${uniqueID} .video-placeholder-text-normal`
    );
    innerTextElement.style.display = "none";

    // Check for TikTok URL
    const isTikTok = htmlElm.src.includes('tiktok.com');
    const youtubeID = !isTikTok && _wccGetYoutubeID(htmlElm.src);
    
    if (youtubeID) {
        addedNode.classList.replace(
            "video-placeholder-normal",
            "video-placeholder-youtube"
        );
        addedNode.style.backgroundImage = `linear-gradient(rgba(76,72,72,.7),rgba(76,72,72,.7)),url('https://img.youtube.com/vi/${youtubeID}/maxresdefault.jpg')`;
        innerTextElement.classList.replace(
            "video-placeholder-text-normal",
            "video-placeholder-text-youtube"
        );
    } else if (isTikTok) {
        addedNode.classList.replace(
            "video-placeholder-text-normal",
            "video-placeholder-tiktok"
        );
        innerTextElement.classList.replace(
            "video-placeholder-text-tiktok",
            "video-placeholder-text-normal"
        );
    }
    // Handle {category} replacement for GDPR law
    if (currentLaw === 'GDPR' && innerTextElement) {
        const originalText = innerTextElement.textContent || innerTextElement.innerText;
        if (originalText?.includes('{category}')) {
            let categoryNames = '';
            
            if (Array.isArray(category)) {
                // Handle multiple categories - get names and join with comma
                categoryNames = category.map(catSlug => {
                    const foundCategory = _wccStore._categories?.find(cat => cat.slug === catSlug);
                    return foundCategory?.name || catSlug || '';
                }).filter(name => name).join(', ');
            } else if (category) {
                // Handle single category
                const foundCategory = _wccStore._categories?.find(cat => cat.slug === category);
                categoryNames = foundCategory?.name || category || '';
            }
            
            innerTextElement.textContent = originalText.replace('{category}', categoryNames.toLowerCase());
        }
    }
}
function _wccGetYoutubeID(src) {
    const match = src.match(
        /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/
    );
    if (match && Array.isArray(match) && match[2] && match[2].length === 11)
        return match[2];
    return false;
}

function _wccSetPlaceHolder() {
    const status = _wccStore._bannerConfig[currentLaw].config.videoPlaceholder.status;
    const styles = _wccStore._bannerConfig[currentLaw].config.videoPlaceholder.styles;
    if (!status) return;
    if (!status) return;
    const placeHolders = document.querySelectorAll(
        `[data-tag="placeholder-title"]`
    );
    if (placeHolders.length < 1) return;
    Array.from(placeHolders).forEach((placeHolder) => {
        placeHolder.style.display = "block";
        placeHolder.addEventListener("click", () => {
            if (ref._wccGetFromStore("action")) _revisitWccConsent();
        });
        for (const style in styles) {
            if (!styles[style]) continue;
            placeHolder.style[style] = styles[style];
        }
    });
}
function _wccAddRtlClass() {
    if (!_wccStore._rtl) return;
    const rtlElements = ['notice', 'detail', 'optout-popup', 'revisit-consent', 'video-placeholder']
    rtlElements.forEach(function (item) {
        _wccGetElementByTag(item) && _wccGetElementByTag(item).classList.add('wcc-rtl');
    });
}

function _wccSetFocus(tagName) {
    const element = _wccGetElementByTag(tagName);
    if (!element) return;
    element.focus();
}

function _wccSetPoweredBy() {
    // Cache configuration access to avoid repeated deep property lookups
    const poweredByStatus = _wccStore._bannerConfig[currentLaw].config.preferenceCenter.poweredBy.status;
    
    // Define powered-by element selectors once
    const poweredBySelectors = ['detail-powered-by', 'optout-powered-by'];
    
    // Determine styles based on powered-by status
    const styles = poweredByStatus ? {
        display: "flex",
        justifyContent: "flex-end",
        alignItems: "center"
    } : {
        display: "none"
    };
    
    // Apply styles to all powered-by elements in a single loop
    poweredBySelectors.forEach((key) => {
        const element = document.querySelector(`[data-tag="${key}"]`);
        if (element) {
            Object.assign(element.style, styles);
        }
    });
}
function _wccWatchBannerElement() {
    document.querySelector("body").addEventListener("click", (event) => {
        const selector = ".wcc-banner-element, .wcc-banner-element *";
        if (
            event.target.matches
                ? event.target.matches(selector)
                : event.target.msMatchesSelector(selector)
        )
            _revisitWccConsent();
    });
}

function _wccRemoveAllDeadCookies() {
    for (const category of _wccStore._categories) {
        if (ref._wccGetFromStore(category.slug) !== "yes")
            _wccRemoveDeadCookies(category);
    }
}
function _wccSetCCPAOptions() {
    const toggle = _wccStore._bannerConfig[currentLaw].config.optOption.toggle;
    const activeColor = toggle.states.active.styles['background-color'];
    const inactiveColor = toggle.states.inactive.styles['background-color'];
    _wccClassRemove("=optout-option", "wcc-disabled", false);
    const toggleDataCode = _wccStore._bannerConfig[currentLaw].settings.shortcodes.find(
        (code) => code.key === "wcc_optout_toggle_label"
    );
    const optOutTitle = _wccStore._bannerConfig[currentLaw].settings.shortcodes.find(
        (code) => code.key === "wcc_optout_option_title"
    );
    const formattedLabel = toggleDataCode.content.replace(
        `[wcc_optout_option_title]`,
        optOutTitle.content
    );
    // Determine checkbox checked status
    let checked = _wccGPCEnabled() || ref._wccGetFromStore("consent") === "yes";  
   
    _wccSetCheckBoxInfo(
        document.getElementById(`wccCCPAOptOut`),
        formattedLabel,
        {
            checked,
            disabled: false,
            addListeners: true,
        },
        { activeColor, inactiveColor },
        true
    );
    if(_wccGPCEnabled() && !ref._wccGetFromStore("action")) {
        const optOutButton = document.querySelector('[data-tag="optout-confirm-button"]');
        if (optOutButton) {
            _wccSetConsentID();
            optOutButton.click();
        } else {
            console.warn("Opt-out confirm button not found.");
        }
    }
}
function _wccSetCheckBoxInfo(
    boxElem,
    formattedLabel,
    { checked, disabled, addListeners },
    { activeColor, inactiveColor },
    isCCPA = false
) {
    if (!boxElem) return;
    if (isCCPA && addListeners)
        _wccAttachListener("=optout-option-title", () => boxElem.click());
    boxElem.checked = checked;
    boxElem.disabled = disabled;
    boxElem.style.backgroundColor = checked ? activeColor : inactiveColor;
    _wccSetCheckBoxAriaLabel(boxElem, checked, formattedLabel, isCCPA);
    if (!addListeners) return;
    boxElem.addEventListener("change", ({ currentTarget: elem }) => {
        const isChecked = elem.checked;
        elem.style.backgroundColor = isChecked ? activeColor : inactiveColor;
        _wccSetCheckBoxAriaLabel(boxElem, isChecked, formattedLabel, isCCPA);
    });
}

window.revisitWccConsent = () => _revisitWccConsent();
window.getWccConsent = function () {
    const cookieConsent = {
        currentLaw: "",
        categories: {},
        isUserActionCompleted: false,
        consentID: "",
        languageCode: ""
      };
      try {
        cookieConsent.currentLaw = _wccGetLaw();
  
        _wccStore._categories.forEach(category => {
            cookieConsent.categories[category.slug] = ref._wccGetFromStore(category.slug) === "yes";
         });
  
        cookieConsent.isUserActionCompleted = ref._wccGetFromStore("action") === "yes";
        cookieConsent.consentID = ref._wccGetFromStore("consentid") || "";
        cookieConsent.languageCode = _wccStore._language || "";
    } catch (e) {}
  
    return cookieConsent;
}; 

/**
 * Record the consent of a visitor.
 * 
 * @returns {void}
 */
async function _wccLogConsent() {
    if (!_wccStore._logConsent) return;
    try {
        const logData = JSON.stringify(
            _wccStore._categories
                .map(({ slug }) => ({
                    name: slug,
                    status: ref._wccGetFromStore(slug) || "no",
                }))
                .concat([
                    {
                        name: "Cookie Consent",
                        status:
                            _wccStore._bannerConfig.activeLaw === "ccpa"
                                ? "yes"
                                : ref._wccGetFromStore("consent") || "no",
                    },
                ])
        );
        const data = {
            log: logData,
            consent_id: ref._wccGetFromStore("consentid"),
        };
        let request = new XMLHttpRequest();
        request.open('POST', `${_wccApi.base}consent_logs`, true);
        request.setRequestHeader('Content-type', 'application/json');
        request.setRequestHeader('X-WP-Nonce', _wccApi.nonce);
        request.send(JSON.stringify(data));
    } catch (err) {
        console.error(err);
    }
}
/**
 * Retrieve the last modified time of a cookie.
 * 
 * @param {string} cookieName - The name of the cookie
 * @returns {number | null} The last modified time of the cookie in milliseconds, or null if the cookie doesn't exist
 */
function _wccGetCookieLastModified(cookieName) {
    const cookieValue = document.cookie
        .split(';')
        .map(cookie => cookie.trim())
        .find(row => row.startsWith(`${cookieName}=`));

    if (cookieValue) {
        const cookiePairs = cookieValue.substring(cookieName.length + 1).split(",");
        for (const pair of cookiePairs) {
            const [key, value] = pair.split(":");
            if (key === 'consent_time') {
                // Try to parse the value associated with the 'consent_time' key as a number
                const lastModifiedTime = Number(value);
                if (!isNaN(lastModifiedTime)) {
                    return lastModifiedTime;
                }
            }
        }
    }
    return null;
}
/**
 * Check if whether plugin Respect Do Not Track & Global Privacy Control
 * 
 * @since 3.2.0
 * @returns {boolean} True if the gpc option enabled in plugin settings and browser settings, false otherwise
 */
function _wccGPCEnabled() {
    return navigator.globalPrivacyControl === true && _wccStore._bannerConfig[currentLaw].config.optOption.gpcOption;
}