(function () {
    if (!window.Wick) return;

    const M_OK = '0000000000000001';
    const M_ZERO_BALANCE = '0000000000000000';
    const M_NOT_RECOGNISED = '1111111111111111';
    const M_LOCKED = '2222222222222222';
    const M_MERCHANT_ISSUE = '3333333333333333';
    const M_EXCHANGE = '4040404040404040';
    const M_EXPIRED = '4444444444444444';
    const M_INVALID = '5555555555555555';
    const M_ADDED = '6666666666666666';
    const M_CONFIG_PROBLEM = '9999999999999999';

    const M_PAY_ERR_101 = '7777777777777101';
    const M_PAY_ERR_102 = '7777777777777102';
    const M_PAY_ERR_103 = '7777777777777103';

    const PAY_ERROR_CARD_MAP = {
        [M_PAY_ERR_101]: 101,
        [M_PAY_ERR_102]: 102,
        [M_PAY_ERR_103]: 103,
    };

    const GIFT_CARDS_LIMIT = 3;
    const BASE_ORDER_TOTAL = 300.0;

    let PAY_ERROR_CODE;

    const mock = {
        orderTotal: BASE_ORDER_TOTAL,
        giftCardTotal: 0.0,
        giftCards: [],
    };

    const toMasked = (num) => `************${String(num || '').slice(-5)}`;

    function recomputeTotalsAndOrder() {
        mock.giftCardTotal = mock.giftCards.reduce(
            (sum, c) => sum + Number(c.amountToRedeem || 0),
            0
        );
        const remaining = Math.max(0, BASE_ORDER_TOTAL - mock.giftCardTotal);
        mock.orderTotal = Number(remaining.toFixed(2));
    }

    function applyWithClamp(requestedAmount) {
        const remaining = Math.max(0, BASE_ORDER_TOTAL - mock.giftCardTotal);
        const applied = Math.min(Number(requestedAmount || 0), remaining);
        return Number(applied.toFixed(2));
    }

    function successPayload() {
        return {
            orderTotal: mock.orderTotal,
            giftCardTotal: mock.giftCardTotal,
            giftCards: mock.giftCards.slice(),
        };
    }

    function getGiftCardErrorCode(giftCardNumber) {
        switch (giftCardNumber) {
            case M_NOT_RECOGNISED:
                return 10;
            case M_LOCKED:
                return 16;
            case M_MERCHANT_ISSUE:
                return 20;
            case M_EXCHANGE:
                return 40;
            case M_EXPIRED:
                return 60;
            case M_INVALID:
                return 99;
            case M_ADDED:
                return 89;
            case M_CONFIG_PROBLEM:
                return -1;
            default:
                return null;
        }
    }

    function addGiftCardMock(giftCardNumber) {
        const errorCode = getGiftCardErrorCode(giftCardNumber);

        if (Number.isFinite(errorCode)) {
            return Promise.reject({ code: errorCode });
        }

        let requested;
        if (giftCardNumber === M_OK) {
            requested = 123.45;
        } else if (giftCardNumber === M_ZERO_BALANCE) {
            requested = 0;
        } else {
            requested = 50.0;
        }

        if (mock.giftCards.length >= GIFT_CARDS_LIMIT) {
            return Promise.reject({ code: 20 });
        }

        const beforeTotal = mock.giftCardTotal;
        const applied = applyWithClamp(requested);

        mock.giftCards.push({
            id: (Date.now() + Math.random()).toString(36),
            maskedNumber: toMasked(giftCardNumber),
            amountToRedeem: applied,
            originalNumber: giftCardNumber,
        });

        if (mock.giftCards.length === GIFT_CARDS_LIMIT) {
            const leftover = Math.max(0, BASE_ORDER_TOTAL - (beforeTotal + applied));
            if (leftover > 0) {
                const last = mock.giftCards[mock.giftCards.length - 1];
                last.amountToRedeem = Number((Number(last.amountToRedeem) + leftover).toFixed(2));
            }
            mock.giftCardTotal = BASE_ORDER_TOTAL;
            mock.orderTotal = 0;
            return Promise.resolve(successPayload());
        }

        recomputeTotalsAndOrder();
        return Promise.resolve(successPayload());
    }

    function removeGiftCardMock(index) {
        const beforeLen = mock.giftCards.length;
        if (index < 0 || index >= beforeLen) return Promise.reject({ code: 20 });

        mock.giftCards.splice(index, 1);
        recomputeTotalsAndOrder();
        return Promise.resolve(successPayload());
    }

    function anyPayErrorCardApplied() {
        for (const gc of mock.giftCards) {
            const code = PAY_ERROR_CARD_MAP[gc.originalNumber];
            if (Number.isFinite(code)) return code;
        }
        return undefined;
    }

    function initGiftCardMock() {
        if (!$('.giftcard-row, .giftcard').length) return;

        $(window).off(Wick.GiftCard.ADD_GIFT_CARD);
        $(window).off(Wick.GiftCard.REMOVE_GIFT_CARD);
        $(window).off(Wick.GiftCard.PAY_WITH_GIFT_CARD);

        $(window).on(Wick.GiftCard.ADD_GIFT_CARD, function (e) {
            const payload = (e.detail && e.detail.payload) || {};
            const giftCardNumber = payload.giftCardNumber;
            setTimeout(function () {
                addGiftCardMock(giftCardNumber)
                    .then(function (p) {
                        e.detail.resolve(Object.assign({ code: 0 }, p));
                    })
                    .catch(function (err) {
                        e.detail.reject(err);
                    });
            }, 1000);
        });

        $(window).on(Wick.GiftCard.REMOVE_GIFT_CARD, function (e) {
            const payload = (e.detail && e.detail.payload) || {};
            const index = Number(payload.index);
            setTimeout(function () {
                removeGiftCardMock(index)
                    .then(function (p) {
                        e.detail.resolve(Object.assign({ code: 0 }, p));
                    })
                    .catch(function (err) {
                        e.detail.reject(err);
                    });
            }, 1000);
        });

        $(window).on(Wick.GiftCard.PAY_WITH_GIFT_CARD, function (e) {
            setTimeout(function () {
                const forcedErrorFromCard = anyPayErrorCardApplied();
                if (Number.isFinite(forcedErrorFromCard)) {
                    return e.detail.reject({
                        errorCode: forcedErrorFromCard,
                        giftCards: mock.giftCards.slice(),
                    });
                }

                if (Number(mock.orderTotal) === 0) {
                    e.detail.resolve({ url: 'page_checkout_confirmation-billie.html' });
                } else {
                    const errorCode = Number.isFinite(PAY_ERROR_CODE) ? PAY_ERROR_CODE : undefined;
                    e.detail.reject({
                        errorCode,
                        giftCards: mock.giftCards.slice(),
                    });
                }
            }, 1000);
        });
    }

    $(document).ready(function () {
        mock.giftCards = [];
        recomputeTotalsAndOrder();

        Wick.GiftCard?.init({
            giftCardsLimit: GIFT_CARDS_LIMIT,
            errorCode: PAY_ERROR_CODE,
            giftCards: mock.giftCards.slice(),
        });
    });

    $(document).ready(initGiftCardMock);
})();
