import { productClick } from '../product-click/athena-product-click.js';
import { athenaConfig, athenaConfigOptions } from '../athena-config.js';
import { refreshDidYouMean } from '../did-you-mean/did-you-mean.js';

/**
 * Handle Html Insert Function
 *
 * @param html
 * @param query
 * @param queryType
 * @returns {DocumentFragment}
 */
function handleHtml(html, query, queryType = null) {
    const template = document.createElement('template');

    if(!html && typeof html !== 'string') {
        throw new Error('Parameter html is required and has to be a type string');
    }

    if(!query && typeof query !== 'string') {
        throw new Error('Parameter query is required and has to be a type string');
    }

    template.innerHTML = html;
    return queryType ?
        template.content.querySelectorAll(`${query}`) :
        template.content.querySelector(`${query}`);
}

/**
 * Setting function for _athena-uid
 *
 * @returns {string}
 */
function setAthenaUid() {
    let token = localStorage.getItem('_athena-uid');

    if (!token) {
        token = Math.random().toString(36).substring(2, 9)
            + '-'
            + Math.random().toString(26).substring(2, 9)
            + '-'
            + Math.random().toString(26).substring(2, 9)
            + '-'
            + Math.random().toString(26).substring(2, 9);

        localStorage.setItem("_athena-uid", token);
    }

    return token;
}

/**
 * Get Cookie Function
 *
 * @param key
 * @returns {string|null}
 */
function getCookie(key) {
    let keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
    return keyValue ? keyValue[2] : null;
}

/**
 * Set Cookie Function
 *
 * @param name
 * @param value
 * @param days
 */
function setCookie(name, value, days) {
    let expires = "";

    if (days) {
        let date = new Date();
        date.setTime(date.getTime() + (days*24*60*60*1000));
        expires = "; expires=" + date.toUTCString();
    }

    document.cookie = name + "=" + (value || "")  + expires + "; path=/";
}

/**
 * Generate Or Get User Token Function
 *
 * @returns {string}
 */
function userToken() {
    let token = getCookie('_athena');

    if (!token) {
        token = 'anonymous-' + Math.random().toString(36).substring(2, 9)
            + '-'
            + Math.random().toString(26).substring(2, 9);

        setCookie('_athena', token, '1');
    }

    return token;
}

/**
 * Delay
 *
 * @param callback
 * @param ms
 * @returns {(function(): void)|*}
 */
function delay(callback, ms) {
    let timer = 0;

    return function () {
        let context = this, args = arguments;
        clearTimeout(timer);

        timer = setTimeout(() => {
            callback.apply(context, args);
        }, ms || 0);
    };
}

/**
 * Refresh Elements On New Request
 */
function refreshElements() {
    const bannerTopSection = document.querySelector('.athena-autocomplete__section-banner-top');
    const bannerBottomSection = document.querySelector('.athena-autocomplete__section-banner-bottom');
    const mainElement = document.querySelector('.athena-autocomplete__flex-container');

    bannerTopSection ? bannerTopSection.remove() : '';
    bannerBottomSection ? bannerBottomSection.remove() : '';
    refreshDidYouMean(true);

    if(mainElement && mainElement.hasChildNodes()) {
        while(mainElement.hasChildNodes()) {
            mainElement.removeChild(mainElement.firstChild);
        }
    }
}

/**
 * Add Loader Autocomplete
 */
function addLoaderAutocomplete() {
    const checkElement = document.querySelector('.athena-spinner-loader');
    if(checkElement) {
        removeLoaderAutocomplete();
    }

    const backgroundOverlayAutocomplete = document.querySelector('.background-overlay-autocomplete');
    backgroundOverlayAutocomplete?.classList.add('autocomplete-overlay');
    //Activate Loader
    const element = document.querySelector('#search_autocomplete');
    //Scroll to top and hide overflow
    element.scrollTop = 0;
    element?.classList.remove('athena-overflow-auto');
    element?.classList.add('athena-overflow-hidden');
    document.body.classList.add('athena-overflow-hidden');

    element.append(handleHtml(`<div class="athena-spinner-loader"></div>`, '.athena-spinner-loader'));
}

/**
 * Remove Loader Autocomplete
 */
function removeLoaderAutocomplete() {
    const loaders = document.querySelectorAll('.athena-spinner-loader');
    loaders.forEach(loader => {
        !loader?.classList.contains('athena-spinner-loader-absolute') && loader?.remove();
    });
    const backgroundOverlayAutocomplete = document.querySelector('.background-overlay-autocomplete');
    backgroundOverlayAutocomplete?.classList.remove('autocomplete-overlay');
    const element = document.querySelector('#search_autocomplete');
    element?.classList.remove('athena-overflow-hidden');
    element?.classList.add('athena-overflow-auto');
    document.body.classList.remove('athena-overflow-hidden');
}


/**
 * Add Loader for Infinite Autocomplete
 */
function addLoaderAutocompleteInfinite() {
    //Activate Loader
    const element = document.querySelector('#search_autocomplete');
    const checkElement = document.querySelector('.athena-spinner-loader-infinite');
    if(!checkElement) {
        element.append(handleHtml(`<div class="athena-spinner-loader-infinite"></div>`, '.athena-spinner-loader-infinite'));
        element?.classList.remove('athena-overflow-auto');
        element?.classList.add('athena-overflow-hidden');
        document.body.classList.add('athena-overflow-hidden');
    }
}

/**
 * Remove Loader Autocomplete
 */
function removeLoaderInfiniteAutocomplete() {
    const loaders = document.querySelectorAll('.athena-spinner-loader-infinite');
    loaders.forEach(loader => {
        loader?.remove();
    });
    const element = document.querySelector('#search_autocomplete');
    element?.classList.remove('athena-overflow-hidden');
    element?.classList.add('athena-overflow-auto');
    document.body.classList.remove('athena-overflow-hidden');
}

/**
 * Get Url Query Param
 *
 * @param query
 * @returns {string}
 */
function getUrlParam(query) {
    const urlParam = new URLSearchParams(window.location.search);
    return urlParam.get(`${query}`);
}

/**
 * Hide Visual Similarity Box
 */
function hideVisualSimilarityBox() {
    const isVisualSimilarityOpen = document.querySelector('#visual_similarity_search')?.classList.contains('athena-helper-show');
    if(isVisualSimilarityOpen) document.querySelector('#visual_similarity_search')?.classList.remove('athena-helper-show');
    if(isVisualSimilarityOpen){
        document.body.classList.remove('open-visual-box');
        if(document.body.classList.contains('edit-croper-open')){
            if(document.querySelector('#cancel_crop_button')){
                document.querySelector('#cancel_crop_button').click();
                document.body.classList.remove('edit-croper-open');
                return;
            }
        }
    }

}

/**
 * Hide Category Menu
 */
function hideCategoryMenu() {
    const isCategoryMenuOpen = document.querySelector('.category-navigation-container')?.classList.contains('active-category-navigation-container');
    if(isCategoryMenuOpen){
        document.querySelector('.category-navigation-container')?.classList.remove('active-category-navigation-container');
        document.querySelector('.category-navigation-btn')?.classList.remove('active-category-navigation-btn');
    }
}

/**
 * Check if Search Page is Active
 *
 * @return {boolean}
 */
function isSearchPageActive() {
    const searchPageContainer = document.querySelector('.athena-landing-page__container');
    return !!searchPageContainer;
}

/**
 * Check Product Click
 *
 * @param event
 */
function checkProductClick(event)
{
    Object.entries(athenaConfigOptions.productDomSelectors).forEach(valueData => {
        const productDomType = valueData[0];
        const productDomSelector = valueData[1];

        if(event.target.classList.contains('find-visual-similar')) return;
        if (event.target.closest(productDomSelector)) {
            productClick(
                event.target.closest(productDomSelector),
                productDomType,
                productDomType === 'search'
            );
        }
    });
}

function populateGlobalObject(isSPA)
{
    function populate()
    {
        athenaConfig.bottomObservedElement = document.querySelector('#athena-search-footer');

        athenaConfigOptions.searchForm = document.querySelector('#search_mini_form');
        athenaConfigOptions.loadPrevContainer = document.querySelector('.athena-search-load-prev');
        athenaConfigOptions.loadPrevBtn = document.querySelector('.athena-search-load-prev button');
        athenaConfigOptions.searchTitle = document.querySelector('.search-title');
        athenaConfigOptions.visualFilters = document.querySelector('.visual-filters');
        athenaConfigOptions.activeFiltersContainer = document.querySelector('.athena-search-active-filters');
        athenaConfigOptions.activeFilterTitle = document.querySelector('.active-filters-title');
        athenaConfigOptions.searchAmount = document.querySelector('.athena-search-amount');
        athenaConfigOptions.pagerContainer = document.querySelector('.athena-search-pagination-container');
        athenaConfigOptions.viewModeContainer = document.querySelector('.athena-search-view');
        athenaConfigOptions.productsPerPage = document.querySelector('.athena-search-products-per-page');
        athenaConfigOptions.productsWrapper = document.querySelector('.products.wrapper');
        athenaConfigOptions.searchProductContainer = document.querySelector('.product-items');
        athenaConfigOptions.searchSidebar = document.querySelector('.athena-sidebar');
        athenaConfigOptions.searchToolbarContainer = document.querySelector('.athena-search-toolbar-sorter');
        athenaConfigOptions.searchBannerContainer = document.querySelector('.athena-search-banner');
        athenaConfigOptions.athenaContent = document.querySelector('#athena-landing-content');
        athenaConfigOptions.athenaSidebar = document.querySelector('#athena-landing-sidebar');
    }

    isSPA ?
        document.addEventListener('SPAContentLoaded', () => populate()) :
        document.addEventListener('DOMContentLoaded', () => populate());
}

function detectSpecialCharacters(value) {
    const specialCharactersPattern = /[<>\/]/;

    return specialCharactersPattern.test(value);
}

/**
 * Add No Results left
 * on autocomplete layout 1 and 2
 * and first click
 */
function addNoResults(container) {
    if(!container) {
        return;
    }

    const noResultsExists = document.querySelector('.autocomplete__product-end');
    if(noResultsExists) {
        return;
    }

    const productContainer = document.querySelector(container);
    if(!productContainer) {
        return;
    }

    productContainer.append(
        handleHtml(`
            <div class="autocomplete__product-end">
                <p class="autocomplete__product-end-p">You have reached the end</p>
            </div>
        `, '.autocomplete__product-end')
    );
}

function handleRenderSearchSuggestions(
    searchSuggestionValue,
    searchValue,
    remove = false
) {
    const searchSuggestionText = document.querySelector('.athena-search-suggestion__text');
    const searchSuggestionTabButton = document.querySelector('.athena-search-suggestion__tab-button');
    const searchSuggestionContainer = document.querySelector('.athena-search-suggestion__container');
    const search = document.querySelector('#search');

    if (!searchSuggestionText || !searchSuggestionTabButton || !searchSuggestionContainer) {
        return;
    }

    if (remove) {
        searchSuggestionTabButton.style.display = 'none';
        searchSuggestionText.innerHTML = '';
        return;
    }

    function normalizeString(str) {
        return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
    }

    function customNormalize(str, replacements) {
        let normalizedStr = normalizeString(str);
        replacements.forEach(([original, replacement]) => {
            const regex = new RegExp(original, 'gi');
            normalizedStr = normalizedStr.replace(regex, replacement);
        });
        return normalizedStr.trim();
    }

    const replacements = [
        ['đ', 'd'],
        ['Đ', 'd'],
        ['Š', 's'],
        ['š', 's'],
    ];

    const normalizedSearchValue = customNormalize(searchValue, replacements);
    const normalizedSearchSuggestionValue = customNormalize(searchSuggestionValue, replacements);

    if (normalizedSearchValue.trim() === normalizedSearchSuggestionValue.trim()) {
        return;
    }

    const regex = new RegExp(`(${normalizedSearchValue})`, 'i');
    searchSuggestionText.innerHTML = normalizedSearchSuggestionValue.replace(regex, `<span style="visibility: hidden;">$1</span>`);
    searchSuggestionTabButton.style.display = 'block';

    [searchSuggestionText, searchSuggestionTabButton, searchSuggestionContainer].forEach(element => {
        element?.addEventListener('click', () => {
            search?.focus();
        });
    });
}

function handleShowMoreLess(
    findClass,
    parentClass,
    from
)
{
    const showMoreButtons = document.querySelectorAll(`${parentClass} .athena-cutoff__show-more-button`);
    const showLessButtons = document.querySelectorAll(`${parentClass} .athena-cutoff__show-less-button`);
    const iconArrows = document.querySelectorAll(`${parentClass} .icon-arrow`);

    if (showMoreButtons.length === 0 || showLessButtons.length === 0 || iconArrows.length === 0) {
        return;
    }

    function getParentContainer(event, findClass)
    {
        if (!event || !findClass) {
            return null;
        }

        const closestSection = event.target.closest(findClass);

        //Custom Logic for layout 3 because layout-3 has search on filters
        if(from === 'layout-3') {
            return closestSection.children.length > 2 ?
                closestSection?.children[1] || null :
                closestSection?.children[0] || null;
        }

        if(from === 'search') {
            return closestSection.children.length > 2 ?
                closestSection?.children[1] || null :
                closestSection?.children[0] || null;
        }

        return closestSection?.children[1] || null;
    }

    function toggleVisibility(
        findClass,
        showButton,
        hideButton,
        expand,
        event,
        isArrow = false,
        arrowIcon = null
    )
    {
        const iconArrow = !isArrow ? event.target.parentElement.querySelector(`${parentClass} .icon-arrow`) : arrowIcon;
        const parentContainer = getParentContainer(event, findClass);

        if (!parentContainer || !iconArrow) {
            return;
        }

        if (expand) {
            parentContainer?.classList.add('expanded');
            iconArrow?.classList.add('arrow-reverse');
        } else {
            parentContainer?.classList.remove('expanded');
            iconArrow?.classList.remove('arrow-reverse');
        }

        showButton?.classList.remove('athena-helper-show');
        hideButton?.classList.add('athena-helper-show');
    }

    iconArrows.forEach(iconArrow => {
        iconArrow.addEventListener('click', (event) => {
            toggleVisibility(
                findClass,
                !iconArrow.classList.contains('arrow-reverse') ? event.target.parentElement.children[0] : event.target.parentElement.children[1],
                !iconArrow.classList.contains('arrow-reverse') ? event.target.parentElement.children[1] : event.target.parentElement.children[0],
                !iconArrow.classList.contains('arrow-reverse'),
                event,
                true,
                iconArrow
            );
        });
    });

    showMoreButtons.forEach(showMoreButton => {
        showMoreButton.addEventListener('click', (event) => {
            toggleVisibility(
                findClass,
                showMoreButton,
                event.target.nextElementSibling,
                true,
                event
            );
        });
    });

    showLessButtons.forEach(showLessButton => {
        showLessButton.addEventListener('click', (event) => {
            toggleVisibility(
                findClass,
                showLessButton,
                event.target.previousElementSibling,
                false,
                event
            );
        });
    });
}

function dispatchSearchDataAnalyticsEvent(
    isVisualSearch,
    isCategory
)
{
    const eventType = isVisualSearch
        ? 'visual-search-data'
        : isCategory
            ? 'category-data'
            : 'search-data';

    window.dispatchEvent(new Event(eventType));
}

function isAppleDevice()
{
    if (navigator.userAgentData?.platform) {
        return /macOS|iOS/i.test(navigator.userAgentData.platform);
    }

    return /Mac|iPhone|iPad|iPod/i.test(navigator.userAgent);
}

const getLazyElements = (
    queryElement = null,
    selectors = null
) =>
{
    if(!selectors || typeof selectors === 'undefined')
        return;

    const lazyElements = new Proxy({}, {
        get: (_, key) => {
            if (selectors.hasOwnProperty(key)) {
                return document.querySelector(selectors[key]);
            }
            return null;
        }
    });

    if (!queryElement) return lazyElements;

    if (Array.isArray(queryElement)) {
        return queryElement.reduce((result, key) => {
            if (selectors.hasOwnProperty(key)) {
                result[key] = document.querySelector(selectors[key]);
            }
            return result;
        }, {});
    }

    return selectors.hasOwnProperty(queryElement)
        ? document.querySelector(selectors[queryElement])
        : null;
};

const isBrave = async () => (navigator.brave && await navigator.brave.isBrave()) || false;

//Exporting all Functions
export {
    handleHtml,
    setAthenaUid,
    getCookie,
    setCookie,
    userToken,
    delay,
    refreshElements,
    addLoaderAutocomplete,
    removeLoaderAutocomplete,
    addLoaderAutocompleteInfinite,
    removeLoaderInfiniteAutocomplete,
    getUrlParam,
    hideVisualSimilarityBox,
    hideCategoryMenu,
    isSearchPageActive,
    checkProductClick,
    populateGlobalObject,
    detectSpecialCharacters,
    addNoResults,
    handleRenderSearchSuggestions,
    handleShowMoreLess,
    dispatchSearchDataAnalyticsEvent,
    isAppleDevice,
    getLazyElements,
    isBrave
}