import Vue from 'vue';
import axios from 'axios';
import { ready } from '@site/js/utils/dom.js';

/**
 * Judopay integration — card form, the loadLibrary patch that creates the
 * hidden iframe on demand, and the Apple Pay / Google Pay Vue components.
 */

/**
 * Dynamically load a `<script>` from `src` and resolve when it has loaded.
 * Replaces the jquery `getScript` API that the original used.
 */
function loadScript(src) {
    return new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = src;
        script.onload = () => resolve();
        script.onerror = () => reject(new Error(`Failed to load script ${src}`));
        document.head.appendChild(script);
    });
}

// --- Standard card form ------------------------------------------------------

ready(() => {
    const btnPay = document.getElementById('submit-payment-button');
    if (!btnPay || typeof Judopay === 'undefined') {
        return;
    }

    let busy = false;

    Judopay.judo.createCardDetails('judopayFormCard', {
        iframe: Judopay.iframe,
    });

    btnPay.addEventListener('click', async () => {
        if (busy) {
            return;
        }

        btnPay.setAttribute('disabled', 'disabled');
        busy = true;

        try {
            const initRes = await axios.get('/shop/checkout/judopay/init/?method=form');
            const init = initRes.data;
            const invoked = await Judopay.judo.invokePayment(init.data.ref, init.data.config);
            const payment = await axios.post(Judopay.urls.payment, invoked);
            window.location.assign(payment.data.redirect);
        } catch (err) {
            const message = err.message
                || err.response?.data?.message
                || 'Your transaction was not successful please try again';
            // eslint-disable-next-line no-alert
            alert(message);
            console.error('[judopay]', err);
        } finally {
            btnPay.removeAttribute('disabled');
            busy = false;
        }
    });
});

// --- Lazy library loader -----------------------------------------------------

ready(() => {
    if (typeof Judopay === 'undefined') {
        return;
    }

    Judopay.loadLibrary = function loadLibrary() {
        if (this.libraryLoaded) {
            return;
        }
        this.libraryLoaded = true;

        const iframe = document.createElement('div');
        iframe.id = 'judopayIframe';
        iframe.style.cssText = 'position:absolute;width:0;height:0;border:0;';
        document.body.prepend(iframe);

        this.judo.createCardDetails('judopayIframe');
    };
});

// --- Apple Pay button --------------------------------------------------------

Vue.component('judopay-apay', {
    props: ['merchantId'],
    data() {
        return {
            ready: false,
            button: null,
            session: null,
        };
    },
    async mounted() {
        if (window.apayLoaded) {
            this.initPayBtn();
            return;
        }
        try {
            await loadScript('https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js');
            window.apayLoaded = true;
            this.initPayBtn();
        } catch (err) {
            window.apayLoaded = false;
            console.error('[judopay-apay] apple-pay-sdk load failed', err);
        }
    },
    methods: {
        async initPayBtn() {
            if (!window.ApplePaySession || !ApplePaySession.canMakePayments()) {
                return;
            }

            try {
                const res = await axios.get('/shop/checkout/judopay/init/?method=apay');
                this.session = res.data.data;

                this.$nextTick(() => {
                    Judopay.loadLibrary();
                    const apayBtn = document.getElementById('judopayAPayBtn');
                    apayBtn?.addEventListener('click', (event) => this.handlePay(event));
                });
            } catch (err) {
                console.error('[judopay-apay] init failed', err);
            }
        },
        handlePay(event) {
            if (!this.session?.ref) {
                return;
            }
            event.preventDefault();

            const vm = this;
            const session = new ApplePaySession(3, vm.session.config.paymentRequest);

            session.onvalidatemerchant = (e) => {
                Judopay.judo.postMessage({
                    params: {
                        apiToken: Judopay.token,
                        sandbox: Judopay.testmode,
                        judoId: Judopay.merchantID,
                        initiativeContext: window.location.hostname,
                        paymentSession: vm.session.ref,
                        validationUrl: e.validationURL,
                    },
                    messageType: 'CREATE_APPLE_PAY_SESSION',
                })
                    .then((res) => {
                        session.completeMerchantValidation(res);
                    })
                    // eslint-disable-next-line no-alert
                    .catch((err) => alert(err));
            };

            session.onshippingcontactselected = async (e) => {
                try {
                    const res = await axios.post('/shop/checkout/judopay/apay/update/', {
                        shippingContact: e.shippingContact,
                    });
                    session.completeShippingContactSelection(res.data);
                } catch (err) {
                    console.error('[judopay-apay] shippingContact update failed', err);
                }
            };

            session.onshippingmethodselected = async (e) => {
                try {
                    const res = await axios.post('/shop/checkout/judopay/apay/update/', {
                        shippingMethod: e.shippingMethod,
                    });
                    session.completeShippingMethodSelection(res.data);
                } catch (err) {
                    console.error('[judopay-apay] shippingMethod update failed', err);
                }
            };

            session.onpaymentauthorized = async (e) => {
                try {
                    const res = await axios.post('/shop/checkout/judopay/apay/authorize/', e.payment);
                    session.completePayment({ status: session.STATUS_SUCCESS });
                    window.location.assign(res.data.redirect);
                } catch (err) {
                    let payload = err.response?.data;
                    if (typeof payload === 'string') {
                        try {
                            payload = JSON.parse(payload);
                        } catch {
                            payload = { message: payload };
                        }
                    }
                    payload = payload || {};

                    const errors = Array.isArray(payload.errors)
                        ? payload.errors.map((o) => new window.ApplePayError(o.code, o.field, o.message))
                        : [
                            new window.ApplePayError(
                                'unknown',
                                'name',
                                payload.message || 'Something went wrong, please try again later!!',
                            ),
                        ];

                    session.completePayment({
                        status: session.STATUS_FAILURE,
                        errors,
                    });
                }
            };

            session.begin();
        },
    },
});

// --- Google Pay button -------------------------------------------------------

Vue.component('judopay-gpay', {
    data() {
        return {
            session: null,
            client: null,
            payload: null,
            allowedPaymentMethods: null,
        };
    },
    async mounted() {
        if (!window.google) {
            try {
                await loadScript('https://pay.google.com/gp/p/js/pay.js');
                this.initPayBtn();
            } catch (err) {
                console.error('[judopay-gpay] pay.js load failed', err);
            }
        } else {
            this.initPayBtn();
        }
    },
    methods: {
        async initPayBtn() {
            const vm = this;
            const container = this.$refs.container;
            if (!container) {
                return;
            }

            try {
                const init = await axios.get('/shop/checkout/judopay/init/?method=gpay');
                const data = init.data.data;
                vm.allowedPaymentMethods = data?.config?.allowedPaymentMethods ?? null;

                vm.client = new google.payments.api.PaymentsClient({
                    environment: data.environment,
                    paymentDataCallbacks: {
                        onPaymentDataChanged(e) {
                            return axios.post('/shop/checkout/judopay/gpay/update/', e)
                                .then((r) => r.data);
                        },
                        onPaymentAuthorized(e) {
                            return axios.post('/shop/checkout/judopay/gpay/authorize/', e)
                                .then((r) => {
                                    vm.payload = r.data.payload;
                                    return r.data;
                                });
                        },
                    },
                });

                const readyRes = await vm.client.isReadyToPay(data.config);
                if (!readyRes.result) {
                    return;
                }

                const buttonOptions = {
                    buttonColor: 'black',
                    buttonLocale: 'en',
                    buttonSizeMode: 'fill',
                    buttonType: 'checkout',
                    onClick: () => vm.handlePay(),
                };
                if (Array.isArray(vm.allowedPaymentMethods)) {
                    buttonOptions.allowedPaymentMethods = vm.allowedPaymentMethods;
                }
                const button = vm.client.createButton(buttonOptions);

                container.appendChild(button);
                button.style.width = '100%';
                button.style.height = '48px';
                Judopay.loadLibrary();
                vm.session = data;
            } catch (err) {
                console.error('[judopay-gpay] init failed', err);
            }
        },
        async handlePay() {
            const vm = this;
            if (!vm.session) {
                return;
            }

            try {
                const paymentData = await vm.client.loadPaymentData(vm.session.config);
                const result = await Judopay.judo.postMessage({
                    params: vm.payload,
                    messageType: 'SUBMIT_GOOGLE_PAY_REQUEST',
                });

                Judopay.judo.digitalWallets.handleGooglePayResult({
                    paymentSession: vm.payload.paymentSession,
                    onError() {
                        window.location.assign('/shop/checkout/judopay/process/?method=gpay');
                    },
                    async onSuccess(payment) {
                        try {
                            await axios.post('/shop/checkout/judopay/payment/?method=gpay', payment);
                        } finally {
                            window.location.assign('/shop/checkout/judopay/process/?method=gpay');
                        }
                    },
                }, paymentData, result);
            } catch (err) {
                console.error('[judopay-gpay] handlePay failed', err);
            }
        },
    },
});
