"use strict";
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.useRoomRateAvailabilityListFromApi = void 0;
const contexts_1 = require("../contexts/index.js");
const events_1 = require("../events/index.js");
const hooks_1 = require("./index.js");
const dayjs_1 = __importDefault(require("dayjs"));
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
const react_1 = require("react");
const FilterProvider_1 = __importDefault(require("../providers/FilterProvider"));
const useSignedInMember_1 = require("./useSignedInMember");
const useRoomRateAvailabilityListFromApi = () => {
    const { hotel } = (0, hooks_1.useCurrentHotel)();
    const ccx = (0, react_1.useContext)(contexts_1.CompanyContext);
    const beContext = (0, react_1.useContext)(contexts_1.BookingEngineContext);
    const { roomstayMember } = (0, react_1.useContext)(contexts_1.RoomstayMemberContext);
    const { attemptSelectUnfilledRow, selectedBasketRow, getAllValidRows, currentBasketRows } = (0, react_1.useContext)(contexts_1.BasketContext);
    const [rooms, setRooms] = (0, react_1.useState)([]);
    const [isLoading, setIsLoading] = (0, react_1.useState)(false);
    const [loadingAttempted, setLoadingAttempted] = (0, react_1.useState)(false);
    const [openRoom, setOpenRoom] = (0, react_1.useState)(null);
    const [apiHasError, setApiHasError] = (0, react_1.useState)(null);
    const startDate = selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getStartDate();
    const endDate = selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getEndDate();
    const promoCode = selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getPromoCode();
    const adults = selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getAdults();
    const children = selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getChildren();
    const infants = selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getInfants();
    const { memberNumber } = (0, useSignedInMember_1.useSignedInMember)();
    const { raise } = (0, hooks_1.useEvent)();
    const retargetingRoom = (0, react_1.useMemo)(() => {
        var _a, _b, _c;
        if (!roomstayMember || ((_a = roomstayMember.bookings) === null || _a === void 0 ? void 0 : _a.length) === 0)
            return null;
        let lastBookingDate;
        let lastBookingRoomcode = '';
        (_c = (_b = roomstayMember.bookings) === null || _b === void 0 ? void 0 : _b.forEach) === null || _c === void 0 ? void 0 : _c.call(_b, (booking) => {
            if (booking.hotelId !== (hotel === null || hotel === void 0 ? void 0 : hotel.hotelID)) {
                return;
            }
            Object.values(booking.itinerary).map((itinerary) => {
                const { roomCode, nights } = itinerary;
                const dates = Object.keys(nights).map(dayjs_1.default);
                const maxDate = (0, dayjs_1.default)(Math.max.apply(null, dates.map((d) => +d)));
                if (!lastBookingDate || maxDate.isAfter(maxDate)) {
                    lastBookingDate = maxDate;
                    lastBookingRoomcode = roomCode;
                }
            });
        });
        return rooms.find((room) => room.code === lastBookingRoomcode);
    }, [rooms, roomstayMember]);
    const getRoomsByBasketRow = (basketRow) => __awaiter(void 0, void 0, void 0, function* () {
        const filters = Object.values(beContext.currentFilters).filter((filter) => !!filter);
        return yield FilterProvider_1.default.getRoomList(basketRow, filters, hotel === null || hotel === void 0 ? void 0 : hotel.hotelID, memberNumber);
    });
    // Used so that we only recalculate the room list when the roomCode or dates of other basket rows change, instead of
    // any change to any basket row.
    const basketRowsRoomDatesKey = (0, react_1.useMemo)(() => {
        return currentBasketRows.map((r) => { var _a, _b; return [(_a = r.getStartDate()) === null || _a === void 0 ? void 0 : _a.format('YYYY-MM-DD'), (_b = r.getEndDate()) === null || _b === void 0 ? void 0 : _b.format('YYYY-MM-DD'), r.getRoomCode()].join('_'); }).join('|');
    }, [currentBasketRows]);
    (0, react_1.useEffect)(() => {
        let isCancelled = false;
        try {
            const search = {
                checkInTime: startDate === null || startDate === void 0 ? void 0 : startDate.format('YYYY-M-D'),
                checkOutTime: endDate === null || endDate === void 0 ? void 0 : endDate.format('YYYY-M-D'),
                numAdults: adults,
                numChildren: children,
                numInfants: infants,
                numRooms: 1,
                promoCode: promoCode,
            };
            const event = new events_1.GuestSearchEvent(search);
            raise(event);
            const filters = Object.values(beContext.currentFilters).filter((filter) => !!filter);
            let row = selectedBasketRow;
            if (!row && !rooms.length) {
                row = attemptSelectUnfilledRow();
            }
            if (!row) {
                const validRows = getAllValidRows();
                row = validRows[validRows.length - 1];
            }
            const onRoomListFinished = () => {
                setLoadingAttempted(true);
                setIsLoading(false);
            };
            if (row) {
                setIsLoading(true);
                // Avoid using .finally() when you need to wait for .then() or .catch() logic to complete —
                // it runs after the Promise settles, but not after those blocks finish executing;
                // instead, manually call your cleanup function at the end of .then() and .catch().
                FilterProvider_1.default.getRoomList(row, filters, hotel === null || hotel === void 0 ? void 0 : hotel.hotelID, memberNumber)
                    .then((rooms) => 
                // Subtract availability already taken by other basket rows
                rooms.map((cacheableRoom) => {
                    var _a;
                    const room = (0, cloneDeep_1.default)(cacheableRoom);
                    const startDate = row.getStartDate();
                    const endDate = row.getEndDate();
                    if (!startDate || !endDate) {
                        return room;
                    }
                    const otherBasketRowsForRoom = getAllValidRows().filter((candidate) => {
                        if (candidate.getID() === (selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getID())) {
                            // We are editing this basket row, so don't count it.
                            return false;
                        }
                        return candidate.getRoomCode() === room.code;
                    });
                    for (const rate of (_a = room.filteredRates) !== null && _a !== void 0 ? _a : []) {
                        for (const date of Object.keys(rate.nightRates)) {
                            for (const otherRow of otherBasketRowsForRoom) {
                                const otherRowStartDate = otherRow.getStartDate();
                                const otherRowEndDate = otherRow.getEndDate();
                                if (!otherRowStartDate || !otherRowEndDate) {
                                    continue;
                                }
                                if ((0, dayjs_1.default)(date).isBetween(otherRowStartDate, otherRowEndDate, 'day', '[)')) {
                                    // @ts-expect-error, the type is wrong :(
                                    rate.nightRates[date].available = Math.max(rate.nightRates[date].available - 1, 0);
                                }
                            }
                        }
                    }
                    return room;
                }))
                    .then((rooms) => rooms.filter((room) => (hotel === null || hotel === void 0 ? void 0 : hotel.showUnavailableRooms) || room.isAvailable()))
                    .then((availableRooms) => {
                    var _a;
                    if (!isCancelled) {
                        setRooms(availableRooms);
                        setOpenRoom(!!selectedBasketRow);
                        setApiHasError(false);
                        const foundRooms = (_a = availableRooms === null || availableRooms === void 0 ? void 0 : availableRooms.map((room) => {
                            var _a, _b;
                            const { name, code } = room;
                            const foundRoom = {
                                name: name,
                                code: code,
                                lowestPrice: room.getLowestPrice(),
                                highestPrice: room.getHighestPrice(),
                                currency: ccx.currentCurrency,
                                rates: (_b = (_a = room.getRates()) === null || _a === void 0 ? void 0 : _a.map((rate) => {
                                    const { name, code } = rate;
                                    return {
                                        name,
                                        code,
                                        price: {
                                            averagePrice: rate.getAveragePrice(),
                                            totalPrice: rate.getTotalPrice(),
                                            currency: ccx.currentCurrency,
                                        },
                                    };
                                })) !== null && _b !== void 0 ? _b : [],
                            };
                            return foundRoom;
                        })) !== null && _a !== void 0 ? _a : [];
                        const event = new events_1.RoomListSearchEvent(search, foundRooms);
                        raise(event);
                        onRoomListFinished();
                    }
                })
                    .catch(() => {
                    if (!isCancelled) {
                        setRooms([]);
                        setOpenRoom(null);
                        setApiHasError(true);
                    }
                    onRoomListFinished();
                });
            }
        }
        catch (ex) {
            //
        }
        return () => {
            setIsLoading(false);
            isCancelled = true;
        };
    }, [
        adults,
        children,
        infants,
        startDate,
        endDate,
        promoCode,
        ccx.currentLanguage,
        beContext.currentFilters,
        selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getStale(),
        memberNumber,
        roomstayMember,
        selectedBasketRow,
        basketRowsRoomDatesKey,
    ]);
    return { loadingAttempted, isLoading, rooms, openRoom, apiHasError, retargetingRoom, getRoomsByBasketRow };
};
exports.useRoomRateAvailabilityListFromApi = useRoomRateAvailabilityListFromApi;
//# sourceMappingURL=RoomRateAvailabilityListFromApi.js.map