/**
 * 2026 Paysera
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 *
 * @author Paysera <plugins@paysera.com>
 * @copyright 2026 Paysera
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 */
(function() {
    'use strict';

    const WINDOW_MODE_NEW_WINDOW = 'new_window';

    const PayseraPaymentMethods = {
        elements: {
            countrySelect: null,
            methodsContainer: null,
            methodsList: null,
            loadingIndicator: null,
            countryInput: null,
            methodInput: null,
            methodError: null
        },

        state: {
            selectedMethod: '',
            selectedCountry: '',
            isLoading: false,
            globalListenersAttached: false,
            popupMessageListenerAttached: false,
            validationAttached: false,
            windowMode: 'same_page',
            paymentResultProcessed: false
        },

        boundHandlers: {
            countryChange: null,
            methodSelection: null
        },

        config: {
            apiUrl: '',
            moduleName: 'payserapayments',
            selectors: {
                countrySelect: 'paysera_country',
                methodsContainer: 'paysera-payment-methods',
                methodsList: 'paysera-payment-methods-list',
                loadingIndicator: 'paysera-loading',
                countryInput: 'input[name="paysera_country_code"]',
                methodInput: 'input[name="paysera_payment_method"]',
                methodRadio: 'paysera_payment_method_radio',
                paymentError: 'paysera-payment-error'
            }
        },

        init() {
            this.loadConfig();
            this.cacheElements();
            if (!this.elements.countrySelect) return;

            this.attachEventListeners();
            this.attachGlobalEventListeners();
            this.attachFormValidation();
            this.setupPaymentWindowMode();
            this.loadMethodsForSelectedCountry();
        },

        loadConfig() {
            const container = document.querySelector('.paysera-country');
            if (container) {
                if (container.dataset.apiUrl) {
                    this.config.apiUrl = container.dataset.apiUrl;
                }
                if (container.dataset.windowMode) {
                    this.state.windowMode = container.dataset.windowMode;
                }
                if (container.dataset.failureUrl) {
                    this.config.failureUrl = container.dataset.failureUrl;
                }
                if (container.dataset.selectMethodError) {
                    this.config.selectMethodError = container.dataset.selectMethodError;
                }
                if (container.dataset.paymentErrorLabel) {
                    this.config.paymentErrorLabel = container.dataset.paymentErrorLabel;
                }
            }

            const select = document.getElementById(this.config.selectors.countrySelect);
            if (select && select.dataset.availableInPrefix) {
                this.config.availableInPrefix = select.dataset.availableInPrefix;
            }
        },

        cacheElements() {
            const { selectors } = this.config;
            this.elements.countrySelect = document.getElementById(selectors.countrySelect);
            this.elements.methodsContainer = document.getElementById(selectors.methodsContainer);
            this.elements.methodsList = document.getElementById(selectors.methodsList);
            this.elements.loadingIndicator = document.getElementById(selectors.loadingIndicator);
            this.elements.countryInput = document.querySelector(selectors.countryInput);
            this.elements.methodInput = document.querySelector(selectors.methodInput);
            this.elements.methodError = null;
        },

        detachEventListeners() {
            if (this.boundHandlers.countryChange) {
                this.elements.countrySelect.removeEventListener('change', this.boundHandlers.countryChange);
                this.elements.countrySelect.removeEventListener('focus', this.boundHandlers.selectFocus);
                this.elements.countrySelect.removeEventListener('blur', this.boundHandlers.selectBlur);
                this.elements.methodsList.removeEventListener('change', this.boundHandlers.methodSelection);
            }
        },

        attachEventListeners() {
            this.boundHandlers.countryChange = (e) => this.handleCountryChange(e);
            this.boundHandlers.selectFocus = () => this.restoreOptionNames();
            this.boundHandlers.selectBlur = () => this.applySelectedPrefix();
            this.boundHandlers.methodSelection = (e) => {
                if (e.target.name === this.config.selectors.methodRadio) {
                    this.handleMethodSelection(e);
                }
            };

            this.elements.countrySelect.addEventListener('change', this.boundHandlers.countryChange);
            this.elements.countrySelect.addEventListener('focus', this.boundHandlers.selectFocus);
            this.elements.countrySelect.addEventListener('blur', this.boundHandlers.selectBlur);
            this.elements.methodsList.addEventListener('change', this.boundHandlers.methodSelection);
        },

        attachGlobalEventListeners() {
            if (this.state.globalListenersAttached) return;
            if (typeof prestashop !== 'undefined') {
                prestashop.on('updatedCart', () => this.reinitialize());
                this.state.globalListenersAttached = true;
            }
        },

        reinitialize() {
            this.detachEventListeners();
            this.loadConfig();
            this.cacheElements();
            if (!this.elements.countrySelect) return;

            this.attachEventListeners();
            this.attachFormValidation();
            this.setupPaymentWindowMode();
            this.loadMethodsForSelectedCountry();
        },

        loadMethodsForSelectedCountry() {
            const countryCode = this.elements.countrySelect.value;
            this.state.selectedCountry = countryCode;
            this.state.selectedMethod = '';
            this.applySelectedPrefix();
            this.updateHiddenInputs(countryCode, '');
            this.fetchPaymentMethods(countryCode);
        },

        handleCountryChange() {
            this.loadMethodsForSelectedCountry();
        },

        updateHiddenInputs(countryCode, methodKey) {
            if (this.elements.countryInput) {
                this.elements.countryInput.value = countryCode;
            }
            if (this.elements.methodInput) {
                this.elements.methodInput.value = methodKey;
            }
        },

        showLoading() {
            this.state.isLoading = true;
            this.elements.countrySelect.disabled = true;
            this.elements.loadingIndicator.style.display = 'block';
            this.elements.methodsContainer.style.display = 'none';
            this.elements.methodsList.innerHTML = '';
            this.elements.loadingIndicator.setAttribute('aria-busy', 'true');
        },

        hideLoading() {
            this.state.isLoading = false;
            this.elements.countrySelect.disabled = false;
            this.elements.loadingIndicator.style.display = 'none';
            this.elements.loadingIndicator.setAttribute('aria-busy', 'false');
        },

        hidePaymentMethods() {
            this.elements.methodsContainer.style.display = 'none';
            this.elements.methodsList.innerHTML = '';
        },

        showPaymentMethods() {
            this.elements.methodsContainer.style.display = 'block';
        },

        async fetchPaymentMethods(countryCode) {
            this.showLoading();

            const abortController = new AbortController();
            const timeoutId = setTimeout(() => abortController.abort(), 10000);

            try {
                const url = `${this.config.apiUrl}?country_code=${encodeURIComponent(countryCode)}`;
                const response = await fetch(url, {
                    method: 'GET',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    signal: abortController.signal,
                });

                clearTimeout(timeoutId);

                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }

                const data = await response.json();
                this.handlePaymentMethodsResponse(data);
            } catch (error) {
                clearTimeout(timeoutId);
                this.handleFetchError(error);
            } finally {
                this.hideLoading();
            }
        },

        handlePaymentMethodsResponse(data) {
            if (data.success && data.methods && data.methods.length > 0) {
                this.renderPaymentMethods(data.methods);
                this.showPaymentMethods();
            } else {
                this.showNoMethodsMessage();
            }
        },

        renderPaymentMethods(methods) {
            this.elements.methodsList.innerHTML = '';
            const fragment = document.createDocumentFragment();

            methods.forEach((method) => {
                const methodItem = this.createMethodElement(method);
                fragment.appendChild(methodItem);
            });

            this.elements.methodsList.appendChild(fragment);
        },

        createMethodElement(method) {
            const container = document.createElement('div');
            container.className = 'paysera-method-item';

            const input = document.createElement('input');
            input.type = 'radio';
            input.name = this.config.selectors.methodRadio;
            input.id = `paysera_method_${this.escapeHtml(method.key)}`;
            input.value = this.escapeHtml(method.key);

            const label = document.createElement('label');
            label.htmlFor = input.id;
            label.className = 'paysera-method-content';

            const logoWrap = document.createElement('div');
            logoWrap.className = 'paysera-method-logo-wrap';
            if (method.logo_url) {
                const img = document.createElement('img');
                img.src = this.escapeHtml(method.logo_url);
                img.alt = this.escapeHtml(method.title);
                img.className = 'paysera-method-logo';
                logoWrap.appendChild(img);
            } else {
                logoWrap.classList.add('paysera-method-logo-wrap--empty');
            }
            label.appendChild(logoWrap);

            const titleDiv = document.createElement('div');
            titleDiv.className = 'paysera-method-title';
            titleDiv.textContent = method.title;
            label.appendChild(titleDiv);

            container.appendChild(input);
            container.appendChild(label);

            return container;
        },

        handleMethodSelection(event) {
            this.state.selectedMethod = event.target.value;
            this.updateHiddenInputs(this.state.selectedCountry, event.target.value);
            this.clearMethodSelectionError();
        },

        showNoMethodsMessage() {
            this.updateHiddenInputs(this.state.selectedCountry, '');

            const container = document.querySelector('.paysera-country');
            const noMethodsText = container && container.dataset.noMethodsText
                ? container.dataset.noMethodsText
                : 'No payment methods available for this country.';

            const message = document.createElement('p');
            message.textContent = noMethodsText;
            this.elements.methodsList.innerHTML = '';
            this.elements.methodsList.appendChild(message);
            this.showPaymentMethods();
        },

        handleFetchError(error) {
            console.error('Paysera payment methods fetch error:', error);
            this.updateHiddenInputs('', '');

            const container = document.querySelector('.paysera-country');
            const errorText = container && container.dataset.errorText
                ? container.dataset.errorText
                : 'Failed to load payment methods. Please try again.';

            const errorMessage = document.createElement('p');
            errorMessage.style.color = 'red';
            errorMessage.textContent = errorText;
            this.elements.methodsList.innerHTML = '';
            this.elements.methodsList.appendChild(errorMessage);
            this.showPaymentMethods();
        },

        applySelectedPrefix() {
            if (!this.config.availableInPrefix) return;

            const select = this.elements.countrySelect;
            const selected = select.options[select.selectedIndex];
            if (!selected) return;

            const originalName = selected.dataset.name || selected.textContent;
            selected.textContent = this.config.availableInPrefix + ' ' + originalName;
        },

        restoreOptionNames() {
            if (!this.config.availableInPrefix) return;

            Array.from(this.elements.countrySelect.options).forEach(option => {
                if (option.dataset.name) {
                    option.textContent = option.dataset.name;
                }
            });
        },

        attachFormValidation() {
            if (this.state.validationAttached) {
                return;
            }

            this.interceptCoreConfirm();
            document.addEventListener('submit', (e) => this.handlePaymentSubmit(e), true);

            this.state.validationAttached = true;
        },

        interceptCoreConfirm() {
            if (typeof prestashop === 'undefined') {
                return;
            }

            prestashop.checkout = prestashop.checkout || {};

            const originalHandler = prestashop.checkout.onCheckOrderableCartResponse;
            const self = this;

            prestashop.checkout.onCheckOrderableCartResponse = function (resp, paymentObject) {
                if (typeof originalHandler === 'function' && originalHandler(resp, paymentObject)) {
                    return true;
                }

                if (!self.isPayseraSelected()) {
                    return false;
                }

                if (!self.isMethodSelected()) {
                    self.showMethodSelectionError();

                    return true;
                }

                self.openPopupIfNeeded();

                return false;
            };
        },

        handlePaymentSubmit(event) {
            const form = event.target;
            if (!this.isPayseraPaymentForm(form) || !this.isPayseraSelected()) {
                return;
            }

            if (!this.isMethodSelected()) {
                event.preventDefault();
                event.stopImmediatePropagation();
                this.showMethodSelectionError();
                return;
            }

            this.openPopupIfNeeded(form);
        },

        openPopupIfNeeded(form) {
            if (this.state.windowMode !== WINDOW_MODE_NEW_WINDOW) {
                return;
            }

            const targetForm = form || this.findMethodForm();
            if (targetForm) {
                this.handlePopupWindowOpen(targetForm);
            }
        },

        findMethodForm() {
            const methodInput = document.querySelector(this.config.selectors.methodInput);

            return methodInput ? methodInput.closest('form') : null;
        },

        isPayseraPaymentForm(form) {
            return form instanceof HTMLFormElement
                && form.querySelector(this.config.selectors.methodInput) !== null;
        },

        isPayseraSelected() {
            const moduleRadio = document.querySelector(
                'input[name="payment-option"][data-module-name="' + this.config.moduleName + '"]'
            );

            if (moduleRadio !== null) {
                return moduleRadio.checked;
            }

            return this.isPayseraFormVisible();
        },

        isPayseraFormVisible() {
            const methodInput = document.querySelector(this.config.selectors.methodInput);
            const form = methodInput ? methodInput.closest('form') : null;

            return form !== null && form.getClientRects().length > 0;
        },

        isMethodSelected() {
            const methodInput = document.querySelector(this.config.selectors.methodInput);

            return !!(methodInput && methodInput.value !== '');
        },

        getMethodErrorElement() {
            if (!this.elements.methodError) {
                this.elements.methodError = document.getElementById(this.config.selectors.paymentError);
            }

            return this.elements.methodError;
        },

        showMethodSelectionError() {
            const errorElement = this.getMethodErrorElement();
            if (!errorElement) {
                return;
            }

            const label = this.config.paymentErrorLabel || 'Payment Error';
            const message = this.config.selectMethodError || 'Please select a Paysera payment method to proceed.';

            errorElement.textContent = '';
            const labelElement = document.createElement('strong');
            labelElement.textContent = label + ':';
            errorElement.appendChild(labelElement);
            errorElement.appendChild(document.createTextNode(' ' + message));

            errorElement.style.display = 'block';
            errorElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
        },

        clearMethodSelectionError() {
            if (this.elements.methodError) {
                this.elements.methodError.style.display = 'none';
            }
        },

        setupPaymentWindowMode() {
            if (this.state.windowMode !== WINDOW_MODE_NEW_WINDOW) {
                return;
            }

            this.attachPopupMessageListener();
        },

        isSameOriginUrl(url) {
            if (typeof url !== 'string' || url.trim() === '') {
                return false;
            }

            try {
                const parsed = new URL(url, window.location.origin);
                return parsed.origin === window.location.origin;
            } catch (e) {
                return false;
            }
        },

        attachPopupMessageListener() {
            if (this.state.popupMessageListenerAttached) {
                return;
            }

            const handlePaymentResult = (data) => {
                if (data && this.isSameOriginUrl(data.redirectUrl)) {
                    this.state.paymentResultProcessed = true;
                    try {
                        localStorage.removeItem('paysera_payment_result');
                    } catch (e) {
                        console.warn('Paysera: failed to clear localStorage', e);
                    }
                    window.location.href = data.redirectUrl;
                }
            };

            window.addEventListener('storage', (event) => {
                if (event.key !== 'paysera_payment_result' || !event.newValue) {
                    return;
                }

                try {
                    handlePaymentResult(JSON.parse(event.newValue));
                } catch (e) {
                    console.warn('Paysera: failed to parse payment result', e);
                }
            });

            window.addEventListener('message', (event) => {
                if (event.origin !== window.location.origin) {
                    return;
                }

                const data = event.data;
                if (data && data.type === 'paysera_payment_complete') {
                    handlePaymentResult(data);
                }
            });

            this.state.popupMessageListenerAttached = true;
        },

        handlePopupWindowOpen(form) {
            this.state.paymentResultProcessed = false;
            const width = 800;
            const height = 600;
            const left = (window.screen.width - width) / 2;
            const top = (window.screen.height - height) / 2;
            const features = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes,status=yes`;

            try {
                localStorage.removeItem('paysera_payment_result');
            } catch (e) {
                console.warn('Paysera: failed to clear localStorage', e);
            }

            const paymentWindow = window.open('about:blank', 'PayseraPaymentWindow', features);

            if (paymentWindow && !paymentWindow.closed) {
                form.target = 'PayseraPaymentWindow';
                try {
                    localStorage.setItem('paysera_popup_active', '1');
                } catch (e) {
                    console.warn('Paysera: failed to write localStorage', e);
                }
                this.monitorPopupWindow(paymentWindow);
            } else {
                form.target = '_self';
            }
        },

        monitorPopupWindow(popupWindow) {
            const checkInterval = setInterval(() => {
                if (!popupWindow || popupWindow.closed) {
                    clearInterval(checkInterval);
                    this.handlePopupClosed();
                }
            }, 500);
        },

        handlePopupClosed() {
            if (this.state.paymentResultProcessed) {
                return;
            }

            try {
                const result = localStorage.getItem('paysera_payment_result');

                if (result) {
                    const data = JSON.parse(result);
                    if (data && this.isSameOriginUrl(data.redirectUrl)) {
                        localStorage.removeItem('paysera_payment_result');
                        window.location.href = data.redirectUrl;
                        return;
                    }
                }
            } catch (e) {
                console.warn('Paysera: failed to read payment result from localStorage', e);
            }

            try {
                localStorage.removeItem('paysera_popup_active');
                localStorage.removeItem('paysera_payment_result');
            } catch (e) {
                console.warn('Paysera: failed to clear localStorage', e);
            }

            if (this.config.failureUrl) {
                const separator = this.config.failureUrl.indexOf('?') !== -1 ? '&' : '?';
                window.location.href = this.config.failureUrl + separator + 'restore=1';
            } else {
                window.location.reload();
            }
        },

        escapeHtml(text) {
            const map = {
                '&': '&amp;',
                '<': '&lt;',
                '>': '&gt;',
                '"': '&quot;',
                "'": '&#039;'
            };
            return String(text).replace(/[&<>"']/g, (m) => map[m]);
        }
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            PayseraPaymentMethods.init();
        });
    } else {
        PayseraPaymentMethods.init();
    }
})();
