"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfirmationStepContextWrapper = void 0;
const contexts_1 = require("../index.js");
const hooks_1 = require("../../hooks/index.js");
const core_1 = require("@roomstay/core");
const ui_1 = require("@roomstay/ui");
const Sentry = __importStar(require("@sentry/browser"));
const types_1 = require("@sentry/types");
const lodash_1 = require("lodash");
const react_1 = __importStar(require("react"));
const react_hook_form_1 = require("react-hook-form");
const react_i18next_1 = require("react-i18next");
const AutoAutoHeight_1 = __importDefault(require("../../animations/AutoAutoHeight"));
const BookingAPI_1 = __importDefault(require("../../api/BookingAPI"));
const Alert_1 = __importStar(require("../../components/generic/Alert"));
const BEButton_1 = __importDefault(require("../../components/generic/BEButton"));
const NextStepButton_1 = __importDefault(require("../../components/generic/buttons/NextStepButton"));
const OverlayLoader_1 = require("../../components/generic/loader/OverlayLoader");
const Text_1 = __importStar(require("../../components/generic/Text"));
const StepConfirmationCheckoutDifferencesModal_1 = __importDefault(require("../../components/steps/confirmation/StepConfirmationCheckoutDifferencesModal"));
const ConfirmationStepContext_1 = require("./ConfirmationStepContext");
const PlacedBookingEvent_1 = require("../../events/actions/PlacedBookingEvent");
const CommittedBookingEvent_1 = require("../../events/views/CommittedBookingEvent");
const RolledBackBookingEvent_1 = require("../../events/views/RolledBackBookingEvent");
const AdyenPaymentHandler_1 = require("../../handlers/payment/AdyenPaymentHandler");
const AfterpayPaymentHandler_1 = require("../../handlers/payment/AfterpayPaymentHandler");
const MastercardPaymentHandler_1 = require("../../handlers/payment/MastercardPaymentHandler");
const PayPalPaymentHandler_1 = require("../../handlers/payment/PayPalPaymentHandler");
const PlanpayPaymentHandler_1 = require("../../handlers/payment/PlanpayPaymentHandler");
const RedirectPaymentHandler_1 = require("../../handlers/payment/RedirectPaymentHandler");
const StripePaymentHandler_1 = require("../../handlers/payment/StripePaymentHandler");
const TrueRewardsPaymentHandler_1 = require("../../handlers/payment/TrueRewardsPaymentHandler");
const VGSMemberPaymentHandler_1 = require("../../handlers/payment/VGSMemberPaymentHandler");
const VGSPaymentHandler_1 = require("../../handlers/payment/VGSPaymentHandler");
const WindcavePaymentHandler_1 = require("../../handlers/payment/WindcavePaymentHandler");
const ConfirmationQuery_1 = require("../../hooks/ConfirmationQuery");
const HistoryConsistentPush_1 = require("../../hooks/HistoryConsistentPush");
const useSignedInMember_1 = require("../../hooks/useSignedInMember");
const CountryCodesAndNumbers_1 = require("../../models/CountryCodesAndNumbers");
const Translation_1 = require("../../translations/Translation");
const DataLayer_1 = __importStar(require("../../util/DataLayer"));
const GetStepRoom_1 = __importDefault(require("../../util/GetStepRoom"));
const ConfirmationStepErrorModal_1 = require("./ConfirmationStepErrorModal");
const ConfirmationStepPriceQuoteErrorModal_1 = require("./ConfirmationStepPriceQuoteErrorModal");
const ConfirmationStepContextProvider = ConfirmationStepContext_1.ConfirmationStepContext.Provider;
const ConfirmationStepContextWrapper = ({ children }) => {
    const [differenceWarning, setDifferenceWarning] = (0, react_1.useState)({
        differences: [],
        warnings: [],
    });
    const { queryRoomstayId: queryReservationId, queryPlanpayCheckoutId, paymentId, isBackFromPlanpay, isBackFromExternalPayment, isInitialCheckout } = (0, ConfirmationQuery_1.useConfirmationQuery)();
    // load the engine context
    const engineContext = (0, react_1.useContext)(contexts_1.BookingEngineContext);
    const { roomstayMember } = (0, contexts_1.useMemberContext)();
    const [bookingSource, setBookingSource] = (0, react_1.useState)();
    const [isLoading, setIsLoading] = (0, react_1.useState)(false);
    const [isPaymentLoading, setIsPaymentLoading] = (0, react_1.useState)(false);
    const [loadingStatus, setLoadingStatus] = (0, react_1.useState)('');
    const [isPaymentFailed, setIsPaymentFailed] = (0, react_1.useState)(false);
    const [customFieldsHaveErrors, setCustomFieldsHaveErrors] = (0, react_1.useState)(false);
    const { isExternalMemberHotel, memberNumber } = (0, useSignedInMember_1.useSignedInMember)();
    const [apiErrorResponse, setApiErrorResponse] = (0, react_1.useState)();
    const [errorModalLoading, setErrorModalLoading] = (0, react_1.useState)(false);
    const [isInPaymentMode, setIsInPaymentMode] = (0, react_1.useState)(false);
    const methods = (0, react_hook_form_1.useForm)({
        mode: 'onSubmit',
    });
    const [errorChecks, setErrorChecks] = (0, react_1.useState)([]);
    const [availablePaymentHandlers, setAvailablePaymentHandlers] = (0, react_1.useState)([]);
    const basketContext = (0, react_1.useContext)(contexts_1.BasketContext);
    const basketRows = basketContext.getAllValidRows();
    const basketAddonRows = basketContext.basketAddonRows;
    const currentSession = (0, react_1.useMemo)(() => {
        return engineContext.sessionProvider.getSession();
    }, [basketContext.reservationData]);
    const { hotel } = (0, hooks_1.useCurrentHotel)();
    const { t } = (0, react_i18next_1.useTranslation)();
    const { raise } = (0, hooks_1.useEvent)();
    const allPaymentHandlers = [
        (0, RedirectPaymentHandler_1.redirectPaymentHandler)(),
        (0, AdyenPaymentHandler_1.adyenPaymentHandler)(),
        (0, VGSPaymentHandler_1.vgsPaymentHandler)(),
        (0, VGSMemberPaymentHandler_1.vgsMemberPaymentHandler)(),
        (0, PlanpayPaymentHandler_1.planpayPaymentHandler)(),
        (0, AfterpayPaymentHandler_1.afterpayPaymentHandler)(),
        (0, MastercardPaymentHandler_1.mastercardPaymentHandler)(),
        (0, TrueRewardsPaymentHandler_1.trueRewardsPaymentHandler)(),
        (0, StripePaymentHandler_1.stripePaymentHandler)(),
        (0, PayPalPaymentHandler_1.paypalPaymentHandler)(),
        (0, WindcavePaymentHandler_1.windcavePaymentHandler)(),
    ];
    const historyConsistentPush = (0, HistoryConsistentPush_1.useHistoryConsistentPush)();
    const paymentMethod = methods.watch('paymentMethod');
    /**
     * We need to make sure that if the user navigates away from this step, we don't try to update the basket
     * with deposit data, as it can cause an unwanted redirect back to this step.
     */
    const confirmationStepIsActiveRef = (0, react_1.useRef)(true);
    (0, react_1.useEffect)(() => {
        return () => {
            confirmationStepIsActiveRef.current = false;
        };
    }, []);
    (0, react_1.useEffect)(() => {
        var _a, _b, _c;
        setBookingSource((_a = engineContext.engine.getSessionProvider().getSession()) === null || _a === void 0 ? void 0 : _a.source);
        const reservationRoomstayId = (_b = basketContext.reservationData) === null || _b === void 0 ? void 0 : _b.roomstayId;
        const isMatchingRoomstayId = !!queryReservationId && (!reservationRoomstayId || queryReservationId === reservationRoomstayId);
        if (isBackFromExternalPayment && isMatchingRoomstayId) {
            if ((_c = basketContext.reservationData.payment) === null || _c === void 0 ? void 0 : _c.isSplitPayment) {
                commitReservation === null || commitReservation === void 0 ? void 0 : commitReservation(basketContext.reservationData);
            }
            else {
                commitReservation === null || commitReservation === void 0 ? void 0 : commitReservation(basketContext.reservationData, 'Please wait... Finalising your reservation');
            }
        }
        if (isBackFromPlanpay && queryReservationId === reservationRoomstayId) {
            commitReservation === null || commitReservation === void 0 ? void 0 : commitReservation(basketContext.reservationData, 'Please wait... Finalising your reservation');
        }
        if (isInitialCheckout) {
            DataLayer_1.default.instance.sendCheckoutView(basketRows, basketAddonRows);
        }
    }, []);
    (0, react_1.useEffect)(() => {
        const requireCall = (hotel === null || hotel === void 0 ? void 0 : hotel.rmsUseDepositQuote) || (hotel === null || hotel === void 0 ? void 0 : hotel.bookingFlow) !== core_1.EBookingFlow.Default;
        // Listen for Basket Row Changes to fetch new deposit quotes on checkout
        if (requireCall && basketContext.quoteQueryID !== '') {
            basketContext.quoteOrPencilReservation(() => confirmationStepIsActiveRef.current);
        }
    }, [hotel === null || hotel === void 0 ? void 0 : hotel.rmsUseDepositQuote, hotel === null || hotel === void 0 ? void 0 : hotel.bookingFlow, basketContext.quoteQueryID]);
    (0, react_1.useEffect)(() => {
        const currentlyAvailablePaymentHandlers = allPaymentHandlers.filter((handler) => handler.isAvailable);
        let defaultPaymentHandler = '';
        if ((roomstayMember === null || roomstayMember === void 0 ? void 0 : roomstayMember.cards) && currentlyAvailablePaymentHandlers.some((handler) => handler.name === 'VGSMember')) {
            defaultPaymentHandler = 'VGSMember';
        }
        if (!defaultPaymentHandler && currentlyAvailablePaymentHandlers.length > 0) {
            defaultPaymentHandler = currentlyAvailablePaymentHandlers[0].name;
        }
        methods.setValue('paymentMethod', defaultPaymentHandler);
        setAvailablePaymentHandlers(currentlyAvailablePaymentHandlers);
    }, [hotel]);
    (0, react_1.useEffect)(() => {
        const selectedPayment = availablePaymentHandlers.find((handler) => handler.name === paymentMethod);
        if (!selectedPayment) {
            return;
        }
        if (selectedPayment.requireBookingPlaced && !selectedPayment.isExclusive) {
            onContinueClick();
        }
    }, [paymentMethod]);
    const exclusivePayment = (0, react_1.useMemo)(() => {
        return availablePaymentHandlers.find((handler) => handler.isExclusive);
    }, [availablePaymentHandlers]);
    const toUserProfiles = (formValues) => {
        return formValues.userProfiles.map((values) => {
            let shortCountryCode = values.CountryCode;
            if (!shortCountryCode) {
                const country = CountryCodesAndNumbers_1.ListOfCountriesAndCodes.find((country) => country.label === values.Country);
                shortCountryCode = country === null || country === void 0 ? void 0 : country.code;
            }
            return {
                title: values.Title,
                firstName: values.Forename,
                lastName: values.Surname,
                phone: values.Phone.replace(' ', ''),
                email: values.Email,
                address: {
                    line1: values.Address,
                    city: values.City,
                    postalCode: values.PostCode,
                    state: values.State,
                    country: values.Country,
                    countryId: values.CountryId,
                    countryCode: shortCountryCode,
                },
                marketingOptIn: formValues.marketingOptIn,
                auxInputs: values.AuxInputs,
            };
        });
    };
    const validateCustomFields = (scrollToInput) => {
        const adhocValid = errorChecks.every((check) => check().validate(scrollToInput));
        return adhocValid === undefined ? true : adhocValid;
    };
    const validateReservation = (data) => __awaiter(void 0, void 0, void 0, function* () {
        const apiDifferences = [];
        if (data.reservations) {
            data.reservations.forEach((reservation, index) => {
                const diff = basketContext.currentBasketRows[index].checkDiffFromReservation(reservation);
                if (diff) {
                    apiDifferences.push(diff);
                }
            });
        }
        else {
            Sentry.addBreadcrumb({
                level: types_1.Severity.Error,
                message: 'No reservation data: ' + JSON.stringify(data),
            });
            throw new Error('The reservation could not be completed due to an unexpected issue, please try again');
        }
        // If there are differences, we want to display them to make sure the booking still needs to proceed
        if (apiDifferences.length || (data.warnings && data.warnings.length)) {
            return {
                differences: apiDifferences,
                warnings: data.warnings,
            };
        }
    });
    const onSubmitSuccess = (data, paymentMethod) => __awaiter(void 0, void 0, void 0, function* () {
        var _a, _b, _c, _d;
        raise(new PlacedBookingEvent_1.PlacedBookingEvent(data, basketContext.currentBasketRows, hotel));
        // If this is a planpay booking, we don't need to do anything else.
        if (paymentMethod === core_1.EBookingPaymentMethod.Planpay || paymentMethod === core_1.EBookingPaymentMethod.TrueRewards) {
            return;
        }
        if ((hotel === null || hotel === void 0 ? void 0 : hotel.cardProcessor) === core_1.EHotelCardProcessor.Passthrough) {
            yield (commitReservation === null || commitReservation === void 0 ? void 0 : commitReservation(data));
        }
        else {
            if ((_b = (_a = data.payment) === null || _a === void 0 ? void 0 : _a.external) === null || _b === void 0 ? void 0 : _b.redirectUrl) {
                redirectOut((_d = (_c = data.payment) === null || _c === void 0 ? void 0 : _c.external) === null || _d === void 0 ? void 0 : _d.redirectUrl);
            }
            else if (!data.payment || Object.keys(data.payment).length === 0) {
                // No payment required (e.g., gift card covers full amount), commit the booking directly
                yield (commitReservation === null || commitReservation === void 0 ? void 0 : commitReservation(data));
            }
        }
    });
    const placeBooking = (formPayload, payment) => __awaiter(void 0, void 0, void 0, function* () {
        DataLayer_1.default.instance.sendInteraction('Complete Booking', DataLayer_1.InteractionType.BUTTON, DataLayer_1.InteractionStep.GUEST_DETAILS);
        setIsLoading(true);
        let data;
        const userProfiles = toUserProfiles(formPayload);
        const perRowExtraFields = formPayload.userProfiles.map((formValue) => {
            var _a;
            return {
                childAges: (_a = formValue.CaptureChildAge) === null || _a === void 0 ? void 0 : _a.filter((age) => age != null).map((age) => parseInt(age, 10)),
            };
        });
        try {
            const captureChildAgeComments = (hotel === null || hotel === void 0 ? void 0 : hotel.captureChildAge)
                ? formPayload.userProfiles.flatMap((formValue, roomIndex) => {
                    var _a;
                    return ((_a = formValue === null || formValue === void 0 ? void 0 : formValue.CaptureChildAge) === null || _a === void 0 ? void 0 : _a.filter((age) => age != null).map((age, childIndex) => `Room ${roomIndex + 1} - Child: ${childIndex + 1} Age: ${age}`)) || [];
                })
                : [];
            const comments = formPayload.comments;
            const bookingComment = captureChildAgeComments.length > 0 ? `${comments}\n${captureChildAgeComments.join('\n')}` : comments;
            const customFields = formPayload === null || formPayload === void 0 ? void 0 : formPayload.customFields;
            data = yield BookingAPI_1.default.Reservation.bookNow(basketRows, userProfiles, payment, basketAddonRows, bookingComment || '', hotel === null || hotel === void 0 ? void 0 : hotel.hotelID, engineContext.sessionProvider.getCurrentSessionID().toString(), basketContext.pencilId, undefined, undefined, undefined, isExternalMemberHotel ? memberNumber : undefined, formPayload.giftCardPreauth, {
                perRow: perRowExtraFields,
                customFields: customFields,
                eta: (formPayload === null || formPayload === void 0 ? void 0 : formPayload.eta) || undefined,
            });
            yield basketContext.booked(data, {
                userProfiles,
                payment,
                comments: bookingComment || '',
                eta: (formPayload === null || formPayload === void 0 ? void 0 : formPayload.eta) || undefined,
            });
            const validationResult = yield validateReservation(data);
            if (validationResult) {
                setIsLoading(false);
                setDifferenceWarning(validationResult);
                return null;
            }
            else {
                yield onSubmitSuccess(data, payment.Method);
                return data;
            }
        }
        catch (error) {
            setApiErrorResponse(error);
        }
        finally {
            setIsLoading(false);
        }
        return null;
    });
    const parseReservationIdsFromData = (data) => {
        var _a;
        return (_a = data === null || data === void 0 ? void 0 : data.reservations) === null || _a === void 0 ? void 0 : _a.map((reservation) => reservation.reservationNumber);
    };
    const commitReservation = (resData, statusUpdate) => __awaiter(void 0, void 0, void 0, function* () {
        try {
            if (statusUpdate) {
                setLoadingStatus(statusUpdate);
            }
            setIsLoading(true);
            if (resData) {
                const reservationIds = parseReservationIdsFromData(resData);
                if (reservationIds.length) {
                    try {
                        const response = yield BookingAPI_1.default.Reservation.commit(reservationIds, resData.itineraryNumber, hotel === null || hotel === void 0 ? void 0 : hotel.hotelID, queryPlanpayCheckoutId || undefined, paymentId || undefined);
                        try {
                            DataLayer_1.default.instance.sendReservationConfirmed(basketContext.getAllValidRows(), basketContext.basketAddonRows, response);
                        }
                        catch (ex) {
                            Sentry.captureException('Failed to read reservations from GTM code: ' + JSON.stringify(ex));
                        }
                        basketContext.checkedOut(response);
                        raise(new CommittedBookingEvent_1.CommittedBookingEvent(resData, basketContext.currentBasketRows, basketContext.basketAddonRows, hotel));
                    }
                    catch (error) {
                        if (error.paymentRequired) {
                            basketContext.additionalPaymentRequired(error.paymentRequired);
                        }
                        else {
                            setApiErrorResponse(error);
                        }
                    }
                }
                else {
                    contexts_1.ErrorHandler.add({ message: t(Translation_1.Translation.Step.Confirmation.UnexpectedErrorOnCommittingReservation) });
                    Sentry.captureException('No reservation IDs found when attempting to commit: ' + JSON.stringify(resData));
                }
            }
        }
        catch (ex) {
            console.error(ex);
            Sentry.captureException(ex);
        }
        setIsLoading(false);
    });
    const rollbackReservation = () => __awaiter(void 0, void 0, void 0, function* () {
        if (!basketContext.reservationData)
            return;
        try {
            const reservationIds = parseReservationIdsFromData(basketContext.reservationData);
            if (reservationIds.length) {
                setIsLoading(true);
                yield BookingAPI_1.default.Reservation.rollback(reservationIds, basketContext.reservationData.itineraryNumber, hotel === null || hotel === void 0 ? void 0 : hotel.hotelID);
                raise(new RolledBackBookingEvent_1.RolledBackBookingEvent(basketContext.reservationData));
            }
            else {
                Sentry.captureException('No reservation IDs found when attempting to rollback: ' + JSON.stringify(basketContext.reservationData));
            }
        }
        catch (ex) {
            console.log('Failed to rollback reservations');
            Sentry.captureException(ex);
        }
        finally {
            basketContext.rollback();
            setIsLoading(false);
        }
    });
    const redirectOut = (targetUrl, stateUpdate) => {
        setIsLoading(true);
        if (stateUpdate) {
            setLoadingStatus(stateUpdate);
        }
        window.location.href = targetUrl;
    };
    const onRetryBooking = () => __awaiter(void 0, void 0, void 0, function* () {
        var _a, _b;
        setErrorModalLoading(true);
        setIsLoading(true);
        const resRequest = currentSession === null || currentSession === void 0 ? void 0 : currentSession.reservationRequest;
        const roomstayId = (_a = currentSession === null || currentSession === void 0 ? void 0 : currentSession.reservation) === null || _a === void 0 ? void 0 : _a.roomstayId;
        if (!resRequest || !roomstayId) {
            console.error('No reservation request or roomstay ID found in session', { resRequest, roomstayId });
            return null;
        }
        try {
            const data = yield BookingAPI_1.default.Reservation.bookNow(basketRows, resRequest.userProfiles, resRequest.payment, basketAddonRows, resRequest.comments, hotel === null || hotel === void 0 ? void 0 : hotel.hotelID, engineContext.sessionProvider.getCurrentSessionID().toString(), basketContext.pencilId, undefined, true, roomstayId, isExternalMemberHotel ? memberNumber : undefined, undefined, {
                perRow: [],
                eta: (resRequest === null || resRequest === void 0 ? void 0 : resRequest.eta) || undefined,
            });
            yield basketContext.booked(data);
            const validationResult = yield validateReservation(data);
            if (validationResult) {
                setIsLoading(false);
            }
            else {
                yield onSubmitSuccess(data, (_b = resRequest.payment) === null || _b === void 0 ? void 0 : _b.Method);
            }
        }
        catch (error) {
            setApiErrorResponse(error);
        }
        finally {
            setIsLoading(false);
            setErrorModalLoading(false);
            setIsPaymentFailed(false);
            setApiErrorResponse(undefined);
        }
    });
    const onErrorModalClose = () => __awaiter(void 0, void 0, void 0, function* () {
        setErrorModalLoading(true);
        // We were previously rolling back reservations here, but deciding against it.
        const params = new URLSearchParams(window.location.search);
        window.history.replaceState({}, '', `${window.location.pathname}?${params}`);
        window.location.reload();
    });
    const attemptFormSubmit = () => new Promise((resolve) => __awaiter(void 0, void 0, void 0, function* () {
        const customFieldValidation = yield validateCustomFields();
        setCustomFieldsHaveErrors(!customFieldValidation);
        const onSuccess = (values) => {
            if (customFieldValidation) {
                resolve(values);
            }
            else {
                resolve(null);
            }
        };
        const onFailure = () => {
            // We can just return because custom fields will handle their own validation
            resolve(null);
        };
        methods.handleSubmit(onSuccess, onFailure)();
    }));
    const onContinueClick = () => __awaiter(void 0, void 0, void 0, function* () {
        // Regardless if we're checking out or getting ready to pay, we need to make sure the details entered are valid
        // so first step will be to validate the inputs.
        var _a, _b, _c;
        const values = yield attemptFormSubmit();
        if (!values) {
            // Error state will be handled within `attemptFormSubmit`
            return;
        }
        if (exclusivePayment) {
            // Since we're in exclusive payment mode we need to decide are we submitting, or enabling the payment stage
            if (isInPaymentMode) {
                setIsPaymentLoading(true);
                const paymentResponse = yield ((_a = exclusivePayment.onConfirm) === null || _a === void 0 ? void 0 : _a.call(exclusivePayment));
                setIsPaymentLoading(false);
                if (paymentResponse.success) {
                    yield commitReservation(basketContext.reservationData, 'Please wait... Finalising your reservation');
                }
                else {
                    // Payment failed. Need to see if user want's to re-try.
                    setIsPaymentFailed(true);
                }
            }
            else {
                if (exclusivePayment.requireBookingPlaced) {
                    yield placeBooking(values, yield (exclusivePayment === null || exclusivePayment === void 0 ? void 0 : exclusivePayment.getBookingPaymentRequestObject()));
                }
                setIsInPaymentMode(true);
                yield ((_b = exclusivePayment.onSelect) === null || _b === void 0 ? void 0 : _b.call(exclusivePayment));
            }
        }
        else {
            // Check if gift card covers the full amount (use absolute value as redemptions are negative)
            const giftCardAmount = Math.abs(((_c = values.giftCardPreauth) === null || _c === void 0 ? void 0 : _c.amount) || 0);
            const totalBookingAmount = basketContext.getTotalPrice() || 0;
            const isFullyCoveredByGiftCard = giftCardAmount > 0 && giftCardAmount >= totalBookingAmount;
            if (isFullyCoveredByGiftCard) {
                // Gift card covers everything, skip payment handler and place booking directly
                yield placeBooking(values, { Method: core_1.EBookingPaymentMethod.Card });
            }
            else {
                // We're not in exclusive payment mode, so we can just submit the form
                // First we need to find the payment object from the selected value
                const paymentMode = availablePaymentHandlers.find((handler) => handler.name === values.paymentMethod);
                if (!paymentMode) {
                    console.error('No payment mode found for selected payment method', { paymentMethod: values.paymentMethod, availablePaymentHandlers });
                    return;
                }
                try {
                    setIsPaymentLoading(true);
                    const response = yield paymentMode.onConfirm();
                    setIsPaymentLoading(false);
                    if (response.success) {
                        const paymentObject = yield (paymentMode === null || paymentMode === void 0 ? void 0 : paymentMode.getBookingPaymentRequestObject());
                        yield placeBooking(values, Object.assign(Object.assign({}, paymentObject), response.data));
                    }
                    else {
                        // The error will be handled in the payment mode.
                    }
                }
                catch (error) {
                    console.error(error);
                }
                finally {
                    setIsPaymentLoading(false);
                }
            }
        }
    });
    const onBackFromPaymentDetails = () => {
        setIsInPaymentMode(false);
    };
    const onClosePriceQuote = () => {
        const params = new URLSearchParams(window.location.search);
        window.history.replaceState({}, '', `${window.location.pathname}?${params}`);
        window.location.reload();
    };
    const onBackPriceQuote = () => {
        historyConsistentPush((0, GetStepRoom_1.default)().getStepUrl());
    };
    const onRetryPriceQuote = () => {
        basketContext.quoteOrPencilReservation(() => confirmationStepIsActiveRef.current);
    };
    return (react_1.default.createElement(react_hook_form_1.FormProvider, Object.assign({}, methods),
        react_1.default.createElement(ConfirmationStepContextProvider, { value: {
                onContinueClick,
                bookingSource,
                commitReservation,
                rollbackReservation,
                redirectOut,
                setLoadingStatus,
                errorChecks,
                addErrorChecks: (...checks) => {
                    setErrorChecks((oldErrors) => (0, lodash_1.unionBy)(checks, oldErrors, (check) => check().name));
                },
                isLoading,
                isBackFromPlanpay,
                isBackFromExternalPayment,
                isInPaymentMode,
                apiErrorResponse,
                availablePaymentHandlers,
            } },
            isLoading && react_1.default.createElement(OverlayLoader_1.OverlayLoader, { isFullscreen: true, label: loadingStatus }),
            react_1.default.createElement(ConfirmationStepErrorModal_1.ConfirmationStepErrorModal, { onRetry: onRetryBooking, onClose: onErrorModalClose, errorData: apiErrorResponse, isLoading: errorModalLoading }),
            react_1.default.createElement(ConfirmationStepPriceQuoteErrorModal_1.ConfirmationStepPriceQuoteErrorModal, { open: basketContext.hasPriceQuoteError, onBack: onBackPriceQuote, onRetry: onRetryPriceQuote, onClose: onClosePriceQuote }),
            react_1.default.createElement(AutoAutoHeight_1.default, { open: customFieldsHaveErrors },
                react_1.default.createElement("div", { className: "u-pad-bottom" },
                    react_1.default.createElement(Alert_1.default, { icon: ui_1.IconType.Error, type: Alert_1.AlertType.Danger },
                        react_1.default.createElement(Text_1.default, { type: Text_1.TextType.Small }, t(Translation_1.Translation.Step.Confirmation.CustomInputFieldError))))),
            children,
            react_1.default.createElement(StepConfirmationCheckoutDifferencesModal_1.default, { differences: differenceWarning.differences, warnings: differenceWarning.warnings, isLoading: isLoading, onClose: () => __awaiter(void 0, void 0, void 0, function* () {
                    yield (rollbackReservation === null || rollbackReservation === void 0 ? void 0 : rollbackReservation());
                    historyConsistentPush((0, GetStepRoom_1.default)().getStepUrl());
                }), onProceed: () => __awaiter(void 0, void 0, void 0, function* () {
                    var _a;
                    const resRequest = currentSession === null || currentSession === void 0 ? void 0 : currentSession.reservationRequest;
                    const resResponse = basketContext.reservationData;
                    try {
                        if (resRequest && resResponse) {
                            yield onSubmitSuccess(resResponse, (_a = resRequest === null || resRequest === void 0 ? void 0 : resRequest.payment) === null || _a === void 0 ? void 0 : _a.Method);
                            setDifferenceWarning({ differences: [], warnings: [] });
                        }
                        else {
                            contexts_1.ErrorHandler.add({ message: t(Translation_1.Translation.Step.Confirmation.UnexpectedErrorOnCommittingReservation) });
                            Sentry.captureException('No reservation request or response found when attempting to commit: ' + JSON.stringify({ resRequest, resResponse }));
                        }
                    }
                    catch (ex) {
                        console.error('Failed to commit reservation', ex);
                        Sentry.captureException(ex);
                    }
                }) }),
            react_1.default.createElement("div", { className: "u-flex u-marg-top--heavy justify-content-end" },
                exclusivePayment && isInPaymentMode && (react_1.default.createElement("div", { className: "u-marg-right d-flex" },
                    react_1.default.createElement(BEButton_1.default, { icon: ui_1.IconType.ArrowLeft, isText: true, onClick: onBackFromPaymentDetails }, t(Translation_1.Translation.Step.Confirmation.EditDetails)))),
                isPaymentFailed && (exclusivePayment === null || exclusivePayment === void 0 ? void 0 : exclusivePayment.name) !== 'Stripe' && (react_1.default.createElement("div", { className: "u-marg-right d-flex" },
                    react_1.default.createElement(BEButton_1.default, { icon: ui_1.IconType.Edit, stopIconAnimation: true, primary: true, filled: true, onClick: onRetryBooking, isLoading: isLoading }, t(Translation_1.Translation.Step.Confirmation.RetryPayment)))),
                (!(exclusivePayment === null || exclusivePayment === void 0 ? void 0 : exclusivePayment.hasCustomConfirmButton) || !isInPaymentMode) && (react_1.default.createElement(NextStepButton_1.default, { disabled: paymentMethod === core_1.EBookingPaymentMethod.Planpay || isLoading || isPaymentLoading || !basketContext.isQuoteOrPencilReady, text: exclusivePayment && !isInPaymentMode ? t(Translation_1.Translation.Step.Confirmation.ContinueToPayment) : t(Translation_1.Translation.Step.Confirmation.ConfirmReservation), isLoading: isLoading || isPaymentLoading || !basketContext.isQuoteOrPencilReady, onClick: onContinueClick }))))));
};
exports.ConfirmationStepContextWrapper = ConfirmationStepContextWrapper;
//# sourceMappingURL=ConfirmationStepContextWrapper.js.map