let razorpayScriptPromise = null;

const loadRazorpayScript = () => {
    if (typeof window === 'undefined') {
        return Promise.reject(new Error('Razorpay is not available in this environment.'));
    }

    if (window.Razorpay) {
        return Promise.resolve();
    }

    if (!razorpayScriptPromise) {
        razorpayScriptPromise = new Promise((resolve, reject) => {
            const existingScript = document.querySelector('script[src="https://checkout.razorpay.com/v1/checkout.js"]');

            if (existingScript) {
                existingScript.addEventListener('load', () => resolve());
                existingScript.addEventListener('error', () => reject(new Error('Failed to load Razorpay script.')));
                return;
            }

            const script = document.createElement('script');
            script.src = 'https://checkout.razorpay.com/v1/checkout.js';
            script.async = true;
            script.onload = () => resolve();
            script.onerror = () => reject(new Error('Failed to load Razorpay script.'));
            document.body.appendChild(script);
        });
    }

    return razorpayScriptPromise;
};

const fetchRazorpayOrder = async (config) => {
    if (!config.fetchOrderUrl) {
        throw new Error('Razorpay order endpoint is not configured.');
    }

    const params = new URLSearchParams();

    if (config.existingOrderId) {
        params.append('order_id', config.existingOrderId);
    }

    const url = params.toString()
        ? `${config.fetchOrderUrl}?${params.toString()}`
        : config.fetchOrderUrl;

    const response = await fetch(url, {
        credentials: 'same-origin',
        headers: {
            'Accept': 'application/json',
        },
    });

    if (!response.ok) {
        throw new Error('Unable to create Razorpay order.');
    }

    const data = await response.json();

    if (!data || !data.token || !data.token.id) {
        throw new Error('Invalid response received from Razorpay order endpoint.');
    }

    return data.token;
};

export default {
    async init(config) {
        if (!config || !config.key) {
            throw new Error('Razorpay key is not configured.');
        }

        await loadRazorpayScript();

        const order = await fetchRazorpayOrder(config);

        return {
            key: config.key,
            name: config.name,
            description: config.description,
            theme: config.theme || {},
            order,
            fetchOrderUrl: config.fetchOrderUrl,
            existingOrderId: config.existingOrderId,
        };
    },

    async createToken(config) {
        if (typeof window === 'undefined' || !window.Razorpay) {
            throw new Error('Razorpay SDK is not loaded.');
        }

        if (!config) {
            throw new Error('Razorpay configuration is missing.');
        }

        if (!config.order || !config.order.id) {
            config.order = await fetchRazorpayOrder(config);
        }

        const billing = config.billing || {};
        const prefillName = [billing.first_name, billing.last_name]
            .filter((value) => !!value)
            .join(' ')
            .trim();

        let resolvePromise;
        let rejectPromise;

        const options = {
            key: config.key,
            order_id: config.order.id,
            amount: config.order.amount,
            currency: config.order.currency,
            name: config.name || undefined,
            description: config.description || undefined,
            theme: config.theme || {},
            prefill: {
                name: prefillName || undefined,
                email: billing.email || undefined,
                contact: billing.phone_number || billing.phone || undefined,
            },
            handler: function (response) {
                if (!response.razorpay_payment_id || !response.razorpay_signature) {
                    return;
                }

                resolvePromise({
                    razorpay_payment_id: response.razorpay_payment_id,
                    razorpay_order_id: response.razorpay_order_id,
                    razorpay_signature: response.razorpay_signature,
                });
            },
            modal: {
                ondismiss: function () {
                    rejectPromise(new Error('Razorpay payment was cancelled.'));
                },
            },
        };

        return new Promise((resolve, reject) => {
            resolvePromise = resolve;
            rejectPromise = reject;

            const razorpayInstance = new window.Razorpay(options);
            razorpayInstance.open();
        });
    },
};
