/** @odoo-module **/

import { _t } from '@web/core/l10n/translation';
import { patch } from '@web/core/utils/patch';
import { rpc } from '@web/core/network/rpc';

import { PaymentForm } from '@payment/interactions/payment_form';

patch(PaymentForm.prototype, {

    setup() {
        super.setup();
        this.poyntFormData = {};
    },

    // #=== DOM MANIPULATION ===#

    async _prepareInlineForm(providerId, providerCode, paymentOptionId, paymentMethodCode, flow) {
        if (providerCode !== 'poynt') {
            await super._prepareInlineForm(...arguments);
            return;
        }

        if (flow === 'token') {
            return;
        }

        this._setPaymentFlow('direct');

        const radio = document.querySelector('input[name="o_payment_radio"]:checked');
        const inlineForm = this._getInlineForm(radio);
        const poyntContainer = inlineForm.querySelector('[name="o_poynt_payment_container"]');

        if (!poyntContainer) {
            return;
        }

        const rawValues = poyntContainer.dataset['poyntInlineFormValues'];
        if (rawValues) {
            this.poyntFormData = JSON.parse(rawValues);
        }

        this._setupCardFormatting(poyntContainer);
        this._setupTerminalToggle(poyntContainer);
    },

    _setupCardFormatting(container) {
        const cardInput = container.querySelector('#poynt_card_number');
        if (cardInput) {
            cardInput.addEventListener('input', (e) => {
                let value = e.target.value.replace(/\D/g, '');
                let formatted = '';
                for (let i = 0; i < value.length && i < 16; i++) {
                    if (i > 0 && i % 4 === 0) {
                        formatted += ' ';
                    }
                    formatted += value[i];
                }
                e.target.value = formatted;
            });
        }

        const expiryInput = container.querySelector('#poynt_expiry');
        if (expiryInput) {
            expiryInput.addEventListener('input', (e) => {
                let value = e.target.value.replace(/\D/g, '');
                if (value.length >= 2) {
                    value = value.substring(0, 2) + '/' + value.substring(2, 4);
                }
                e.target.value = value;
            });
        }
    },

    _setupTerminalToggle(container) {
        const terminalCheckbox = container.querySelector('#poynt_use_terminal');
        const terminalSelect = container.querySelector('#poynt_terminal_select_wrapper');
        const cardFields = container.querySelectorAll(
            '#poynt_card_number, #poynt_expiry, #poynt_cvv, #poynt_cardholder'
        );

        if (!terminalCheckbox) {
            return;
        }

        terminalCheckbox.addEventListener('change', () => {
            if (terminalCheckbox.checked) {
                if (terminalSelect) {
                    terminalSelect.style.display = 'block';
                }
                cardFields.forEach(f => {
                    f.closest('.mb-3').style.display = 'none';
                    f.removeAttribute('required');
                });
                this._loadTerminals(container);
            } else {
                if (terminalSelect) {
                    terminalSelect.style.display = 'none';
                }
                cardFields.forEach(f => {
                    f.closest('.mb-3').style.display = 'block';
                    if (f.id !== 'poynt_cardholder') {
                        f.setAttribute('required', 'required');
                    }
                });
            }
        });
    },

    async _loadTerminals(container) {
        const selectEl = container.querySelector('#poynt_terminal_select');
        if (!selectEl || selectEl.options.length > 1) {
            return;
        }

        try {
            const terminals = await rpc('/payment/poynt/terminals', {
                provider_id: this.poyntFormData.provider_id,
            });

            selectEl.innerHTML = '';
            if (terminals && terminals.length > 0) {
                terminals.forEach(t => {
                    const option = document.createElement('option');
                    option.value = t.id;
                    option.textContent = `${t.name} (${t.status})`;
                    selectEl.appendChild(option);
                });
            } else {
                const option = document.createElement('option');
                option.value = '';
                option.textContent = _t('No terminals available');
                selectEl.appendChild(option);
            }
        } catch {
            const option = document.createElement('option');
            option.value = '';
            option.textContent = _t('Failed to load terminals');
            selectEl.appendChild(option);
        }
    },

    // #=== PAYMENT FLOW ===#

    async _initiatePaymentFlow(providerCode, paymentOptionId, paymentMethodCode, flow) {
        if (providerCode !== 'poynt' || flow === 'token') {
            await super._initiatePaymentFlow(...arguments);
            return;
        }

        const radio = document.querySelector('input[name="o_payment_radio"]:checked');
        const inlineForm = this._getInlineForm(radio);
        const useTerminal = inlineForm.querySelector('#poynt_use_terminal');

        if (useTerminal && useTerminal.checked) {
            const terminalId = inlineForm.querySelector('#poynt_terminal_select').value;
            if (!terminalId) {
                this._displayErrorDialog(
                    _t("Terminal Required"),
                    _t("Please select a terminal device."),
                );
                this._enableButton();
                return;
            }
        } else {
            const validationError = this._validateCardInputs(inlineForm);
            if (validationError) {
                this._displayErrorDialog(
                    _t("Invalid Card Details"),
                    validationError,
                );
                this._enableButton();
                return;
            }
        }

        await super._initiatePaymentFlow(...arguments);
    },

    _validateCardInputs(inlineForm) {
        const cardNumber = inlineForm.querySelector('#poynt_card_number');
        const expiry = inlineForm.querySelector('#poynt_expiry');
        const cvv = inlineForm.querySelector('#poynt_cvv');

        const cardDigits = cardNumber.value.replace(/\D/g, '');
        if (cardDigits.length < 13 || cardDigits.length > 19) {
            return _t("Please enter a valid card number.");
        }

        const expiryValue = expiry.value;
        if (!/^\d{2}\/\d{2}$/.test(expiryValue)) {
            return _t("Please enter a valid expiry date (MM/YY).");
        }

        const [month, year] = expiryValue.split('/').map(Number);
        if (month < 1 || month > 12) {
            return _t("Invalid expiry month.");
        }

        const now = new Date();
        const expiryDate = new Date(2000 + year, month);
        if (expiryDate <= now) {
            return _t("Card has expired.");
        }

        const cvvValue = cvv.value.replace(/\D/g, '');
        if (cvvValue.length < 3 || cvvValue.length > 4) {
            return _t("Please enter a valid CVV.");
        }

        return null;
    },

    async _processDirectFlow(providerCode, paymentOptionId, paymentMethodCode, processingValues) {
        if (providerCode !== 'poynt') {
            await super._processDirectFlow(...arguments);
            return;
        }

        const radio = document.querySelector('input[name="o_payment_radio"]:checked');
        const inlineForm = this._getInlineForm(radio);
        const useTerminal = inlineForm.querySelector('#poynt_use_terminal');

        if (useTerminal && useTerminal.checked) {
            await this._processTerminalPayment(processingValues, inlineForm);
        } else {
            await this._processCardPayment(processingValues, inlineForm);
        }
    },

    async _processCardPayment(processingValues, inlineForm) {
        const cardNumber = inlineForm.querySelector('#poynt_card_number').value.replace(/\D/g, '');
        const expiry = inlineForm.querySelector('#poynt_expiry').value;
        const cvv = inlineForm.querySelector('#poynt_cvv').value;
        const cardholder = inlineForm.querySelector('#poynt_cardholder').value;

        const [expMonth, expYear] = expiry.split('/').map(Number);

        try {
            const result = await rpc('/payment/poynt/process_card', {
                reference: processingValues.reference,
                poynt_order_id: processingValues.poynt_order_id,
                card_number: cardNumber,
                exp_month: expMonth,
                exp_year: 2000 + expYear,
                cvv: cvv,
                cardholder_name: cardholder,
            });

            if (result.error) {
                this._displayErrorDialog(
                    _t("Payment Failed"),
                    result.error,
                );
                this._enableButton();
                return;
            }

            window.location.href = processingValues.return_url;
        } catch (error) {
            this._displayErrorDialog(
                _t("Payment Processing Error"),
                error.message || _t("An unexpected error occurred."),
            );
            this._enableButton();
        }
    },

    async _processTerminalPayment(processingValues, inlineForm) {
        const terminalId = inlineForm.querySelector('#poynt_terminal_select').value;

        try {
            const result = await rpc('/payment/poynt/send_to_terminal', {
                reference: processingValues.reference,
                terminal_id: parseInt(terminalId),
                poynt_order_id: processingValues.poynt_order_id,
            });

            if (result.error) {
                this._displayErrorDialog(
                    _t("Terminal Payment Failed"),
                    result.error,
                );
                this._enableButton();
                return;
            }

            this._showTerminalWaitingScreen(processingValues, terminalId);
        } catch (error) {
            this._displayErrorDialog(
                _t("Terminal Error"),
                error.message || _t("Failed to send payment to terminal."),
            );
            this._enableButton();
        }
    },

    _showTerminalWaitingScreen(processingValues, terminalId) {
        const container = document.querySelector('.o_poynt_payment_form');
        if (container) {
            container.innerHTML = `
                <div class="text-center p-4">
                    <div class="spinner-border text-primary mb-3" role="status">
                        <span class="visually-hidden">Loading...</span>
                    </div>
                    <h5>${_t("Waiting for terminal payment...")}</h5>
                    <p class="text-muted">
                        ${_t("Please complete the payment on the terminal device.")}
                    </p>
                    <p class="text-muted small" id="poynt_terminal_status">
                        ${_t("Checking status...")}
                    </p>
                </div>
            `;
        }

        this._pollTerminalStatus(processingValues, terminalId);
    },

    async _pollTerminalStatus(processingValues, terminalId, attempt = 0) {
        const maxAttempts = 60;
        const pollInterval = 3000;

        if (attempt >= maxAttempts) {
            this._displayErrorDialog(
                _t("Timeout"),
                _t("Terminal payment timed out. Please check the device."),
            );
            this._enableButton();
            return;
        }

        try {
            const result = await rpc('/payment/poynt/terminal_status', {
                reference: processingValues.reference,
                terminal_id: parseInt(terminalId),
            });

            const statusEl = document.getElementById('poynt_terminal_status');

            if (result.status === 'CAPTURED' || result.status === 'AUTHORIZED') {
                if (statusEl) {
                    statusEl.textContent = _t("Payment completed! Redirecting...");
                }
                window.location.href = processingValues.return_url;
                return;
            }

            if (result.status === 'DECLINED' || result.status === 'FAILED') {
                this._displayErrorDialog(
                    _t("Payment Declined"),
                    _t("The payment was declined at the terminal."),
                );
                this._enableButton();
                return;
            }

            if (statusEl) {
                statusEl.textContent = _t("Status: ") + (result.status || _t("Pending"));
            }

            setTimeout(
                () => this._pollTerminalStatus(processingValues, terminalId, attempt + 1),
                pollInterval,
            );
        } catch {
            setTimeout(
                () => this._pollTerminalStatus(processingValues, terminalId, attempt + 1),
                pollInterval,
            );
        }
    },

});
