"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.default = DatePicker;
const contexts_1 = require("../../../contexts/index.js");
const hooks_1 = require("../../../hooks/index.js");
const classnames_1 = __importDefault(require("classnames"));
const dayjs_1 = __importDefault(require("dayjs"));
const react_1 = __importStar(require("react"));
const react_i18next_1 = require("react-i18next");
const Translation_1 = require("translations/Translation");
const BookingAPI_1 = __importDefault(require("../../../api/BookingAPI"));
const CalendarHighlightLegend_1 = __importDefault(require("./CalendarHighlightLegend/CalendarHighlightLegend"));
const DatePickerMonth_1 = __importDefault(require("./DatePickerMonth"));
const Icon_1 = __importStar(require("../Icon/Icon"));
const DaysSelectedInformer_1 = __importDefault(require("../../steps/DaysSelectedInformer"));
const MinimumNightStayPill_1 = __importDefault(require("../../steps/MinimumNightStayPill"));
const useSignedInMember_1 = require("../../../hooks/useSignedInMember");
const DatePickerTypeFeature_1 = __importDefault(require("../../../providers/feature/DatePickerTypeFeature"));
const Color_1 = require("../../../util/Color");
const DataLayer_1 = __importStar(require("../../../util/DataLayer"));
const WeekViewSkeleton_1 = __importDefault(require("./WeekViewSkeleton"));
const DatePickerWeek = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./DatePickerWeek'))));
var DateRangePickingState;
(function (DateRangePickingState) {
    DateRangePickingState[DateRangePickingState["StartDate"] = 1] = "StartDate";
    DateRangePickingState[DateRangePickingState["EndDate"] = 2] = "EndDate";
})(DateRangePickingState || (DateRangePickingState = {}));
// FIXME: there is a fragile race condition where if when the start date is selected it makes an API call the picker state won't be updated
function DatePicker(props) {
    var _a, _b;
    const { hotel } = (0, hooks_1.useCurrentHotel)();
    const { memberNumber } = (0, useSignedInMember_1.useSignedInMember)();
    const { t } = (0, react_i18next_1.useTranslation)();
    const getInitialMonth = () => { var _a, _b; return (_b = (_a = props.showMonthOnLoad) !== null && _a !== void 0 ? _a : props.selectedStartDate) !== null && _b !== void 0 ? _b : (0, dayjs_1.default)(); };
    const [currentMonth, setCurrentMonth] = (0, react_1.useState)(getInitialMonth());
    const [selectedStartDate, setSelectedStartDate] = (0, react_1.useState)((_a = props.selectedStartDate) !== null && _a !== void 0 ? _a : null);
    const [selectedEndDate, setSelectedEndDate] = (0, react_1.useState)((_b = props.selectedEndDate) !== null && _b !== void 0 ? _b : null);
    (0, react_1.useEffect)(() => {
        var _a;
        // Sync selectedStartDate when props.selectedStartDate changes
        setSelectedStartDate((_a = props.selectedStartDate) !== null && _a !== void 0 ? _a : null);
        // Optionally update the calendar's current month based on the new start date, allows the calendar to jump to a different month if `props.selectedStartDate`  belongs to another month (currently disabled).
        // setCurrentMonth(getInitialMonth());
    }, [props.selectedStartDate]);
    (0, react_1.useEffect)(() => {
        var _a;
        // Sync selectedEndDate when props.selectedEndDate changes
        setSelectedEndDate((_a = props.selectedEndDate) !== null && _a !== void 0 ? _a : null);
    }, [props.selectedEndDate]);
    const [hoveringOverDate, setHoveringOverDate] = (0, react_1.useState)(null);
    const [pickingState, setPickingState] = (0, react_1.useState)(DateRangePickingState.StartDate);
    const [calendarStyle, setCalendarStyle] = (0, react_1.useState)((hotel === null || hotel === void 0 ? void 0 : hotel.defaultDatepickerType) ? hotel === null || hotel === void 0 ? void 0 : hotel.defaultDatepickerType : 'Month');
    (0, react_1.useEffect)(() => {
        setCalendarStyle((hotel === null || hotel === void 0 ? void 0 : hotel.defaultDatepickerType) ? hotel === null || hotel === void 0 ? void 0 : hotel.defaultDatepickerType : 'Month');
    }, [hotel === null || hotel === void 0 ? void 0 : hotel.defaultDatepickerType]);
    const [months, setMonths] = (0, react_1.useState)(props.showMultipleMonths ? [currentMonth, currentMonth.add(1, 'month')] : [currentMonth]);
    const [maxPrice, setMaxPrice] = (0, react_1.useState)(0);
    const basketContext = (0, react_1.useContext)(contexts_1.BasketContext);
    const { getLastValidDay, getArrivalNightStay } = (0, hooks_1.useCalendarNightStay)({ basketContext });
    const [nightStayValidation, setNightStayValidation] = (0, react_1.useState)({
        init: false,
        arrivalMinNightStay: null,
        arrivalMaxNightStay: null,
        validationMinNightStay: null,
        validationMaxNightStay: null,
    });
    const [arrivalNightStay, setArrivalNightStay] = (0, react_1.useState)({
        arrivalMinNightStay: null,
        arrivalMaxNightStay: null,
    });
    const { selectedBasketRow } = basketContext;
    const roomCode = (0, react_1.useMemo)(() => {
        var _a, _b;
        return (_b = (_a = props === null || props === void 0 ? void 0 : props.roomCode) !== null && _a !== void 0 ? _a : selectedBasketRow === null || selectedBasketRow === void 0 ? void 0 : selectedBasketRow.getRoomCode()) !== null && _b !== void 0 ? _b : '';
    }, [props === null || props === void 0 ? void 0 : props.roomCode, selectedBasketRow]);
    const rateCode = (0, react_1.useMemo)(() => {
        return props.rateCode || '';
    }, [props.rateCode]);
    const onClickDate = (newDate) => __awaiter(this, void 0, void 0, function* () {
        let newPickingState = null;
        const adults = selectedBasketRow ? selectedBasketRow.getAdults() : 0;
        const children = selectedBasketRow ? selectedBasketRow.getChildren() : 0;
        const infants = selectedBasketRow ? selectedBasketRow.getInfants() : 0;
        const promoCode = selectedBasketRow ? selectedBasketRow.getPromoCode() : '';
        const newDatePrice = yield BookingAPI_1.default.Availability.getCheapestPriceForDay(newDate, adults, children, infants, promoCode, roomCode, rateCode, hotel === null || hotel === void 0 ? void 0 : hotel.hotelID, memberNumber, false);
        switch (pickingState) {
            default:
            case DateRangePickingState.StartDate:
                if ((newDatePrice === null || newDatePrice === void 0 ? void 0 : newDatePrice.price) || !hotel) {
                    newPickingState = DateRangePickingState.EndDate;
                    setSelectedStartDate(newDate);
                    const result = yield getArrivalNightStay(newDate, roomCode, rateCode);
                    setArrivalNightStay(result);
                    setSelectedEndDate(null);
                }
                break;
            case DateRangePickingState.EndDate:
                if (!newDate)
                    break;
                if (newDate.isBefore(selectedStartDate)) {
                    setSelectedStartDate(newDate);
                    newPickingState = DateRangePickingState.EndDate;
                }
                else {
                    const result = yield getLastValidDay(selectedStartDate, newDate, roomCode, rateCode);
                    setNightStayValidation(result.nightStayValidation);
                    if (!result.isValidNightStay)
                        break;
                    newPickingState = DateRangePickingState.StartDate;
                    setHoveringOverDate(null);
                    if (newDate.isSame(selectedStartDate)) {
                        setSelectedEndDate(result.lastValidDay.add(1, 'day'));
                    }
                    else {
                        setSelectedEndDate(result.lastValidDay);
                    }
                }
                break;
        }
        if (props.supportsMultiSelecting) {
            setPickingState(newPickingState);
        }
    });
    const onHoveredOverDay = (day) => {
        if (selectedStartDate && !selectedEndDate) {
            getLastValidDay(selectedStartDate, day, roomCode, rateCode).then((result) => {
                setNightStayValidation(result.nightStayValidation);
                setHoveringOverDate(result.lastValidDay);
            });
        }
    };
    const firstUpdate = (0, react_1.useRef)(null);
    // TODO: Perhaps refactor this later to not depend on non-state items
    (0, react_1.useEffect)(() => {
        if ((DatePickerTypeFeature_1.default === null || DatePickerTypeFeature_1.default === void 0 ? void 0 : DatePickerTypeFeature_1.default.isActive()) && props.supportsWeek) {
            setCalendarStyle('Week');
        }
    }, [DatePickerTypeFeature_1.default === null || DatePickerTypeFeature_1.default === void 0 ? void 0 : DatePickerTypeFeature_1.default.isActive()]);
    (0, react_1.useEffect)(() => {
        if (props.showMonthOnLoad) {
            setCurrentMonth(props.showMonthOnLoad);
        }
    }, [props.showMonthOnLoad]);
    (0, react_1.useEffect)(() => {
        if (props.showMultipleMonths) {
            setMonths([currentMonth, currentMonth.add(1, 'month')]);
        }
    }, [currentMonth, props.showMultipleMonths]);
    (0, react_1.useEffect)(() => {
        if (firstUpdate.current) {
            firstUpdate.current = null;
            return;
        }
        if (props.onStartDateChanged) {
            props.onStartDateChanged(selectedStartDate);
        }
    }, [selectedStartDate]);
    (0, react_1.useLayoutEffect)(() => {
        if (firstUpdate.current) {
            firstUpdate.current = null;
            return;
        }
        if (props.onEndDateChanged) {
            props.onEndDateChanged(selectedEndDate, {
                validationMinNightStay: nightStayValidation.validationMinNightStay,
                validationMaxNightStay: nightStayValidation.validationMaxNightStay,
            });
        }
    }, [selectedEndDate]);
    const nightStayRequirements = (0, react_1.useMemo)(() => {
        const check = {
            MinNightStayRequired: false,
            MaxNightStayRequired: false,
        };
        const options = {
            minNightStay: arrivalNightStay.arrivalMinNightStay,
            maxNightStay: arrivalNightStay.arrivalMaxNightStay,
        };
        if (selectedStartDate) {
            if (((arrivalNightStay === null || arrivalNightStay === void 0 ? void 0 : arrivalNightStay.arrivalMinNightStay) && !selectedEndDate) || ((nightStayValidation === null || nightStayValidation === void 0 ? void 0 : nightStayValidation.validationMinNightStay) && selectedEndDate)) {
                check.MinNightStayRequired = true;
            }
            if (((arrivalNightStay === null || arrivalNightStay === void 0 ? void 0 : arrivalNightStay.arrivalMaxNightStay) && !selectedEndDate) || ((nightStayValidation === null || nightStayValidation === void 0 ? void 0 : nightStayValidation.validationMaxNightStay) && selectedEndDate)) {
                check.MaxNightStayRequired = true;
            }
        }
        if (check.MinNightStayRequired && check.MaxNightStayRequired) {
            return [t(Translation_1.Translation.Step.Date.NightStayRequirement.BothMinMaxNightStayRequired, options)];
        }
        if (check.MinNightStayRequired) {
            return [t(Translation_1.Translation.Step.Date.NightStayRequirement.MinNightStayRequired, options)];
        }
        if (check.MaxNightStayRequired) {
            return [t(Translation_1.Translation.Step.Date.NightStayRequirement.MaxNightStayRequired, options)];
        }
        return [];
    }, [selectedStartDate, selectedEndDate, arrivalNightStay, nightStayValidation]);
    const context = {
        today: (0, dayjs_1.default)(),
        todayInUnix: (0, dayjs_1.default)().unix(),
        startDate: selectedStartDate,
        endDate: selectedEndDate,
        hoveredMonth: hoveringOverDate,
        maxPrice,
        onHoverOver: onHoveredOverDay,
        currentMonth,
        onDayClicked: (date) => {
            onClickDate(date);
        },
        setMaxPrice,
        arrivalNightStay,
        nightStayValidation,
        nightStayRequirements,
        roomCode: roomCode,
        rateCode: rateCode,
    };
    const printMonths = (0, react_1.useMemo)(() => (react_1.default.createElement(react_1.default.Fragment, null, calendarStyle === 'Month' ? (react_1.default.createElement(react_1.default.Fragment, null,
        react_1.default.createElement(DatePickerMonth_1.default, { small: props.small, showingMonth: currentMonth, readOnly: props.readOnly }),
        props.showMultipleMonths && react_1.default.createElement(DatePickerMonth_1.default, { showingMonth: currentMonth.add(1, 'month'), readOnly: props.readOnly }))) : (react_1.default.createElement(react_1.default.Fragment, null,
        react_1.default.createElement(react_1.default.Suspense, { fallback: react_1.default.createElement(WeekViewSkeleton_1.default, null) },
            react_1.default.createElement(DatePickerWeek, null)))))), [currentMonth, props.showMultipleMonths, calendarStyle, props.readOnly, roomCode]);
    const calendarClassNames = (0, classnames_1.default)('diji-calendar', {
        '--single': !props.showMultipleMonths,
        '--small': props.small,
        '--week': calendarStyle === 'Week',
    }, props === null || props === void 0 ? void 0 : props.className);
    const previousMonthOnClick = () => {
        DataLayer_1.default.instance.sendInteraction('Show Previous Month', DataLayer_1.InteractionType.CALENDAR, DataLayer_1.InteractionStep.DATES);
        setCurrentMonth(currentMonth.subtract(1, 'month'));
    };
    const nextMonthOnClick = () => {
        DataLayer_1.default.instance.sendInteraction('Show Next Month', DataLayer_1.InteractionType.CALENDAR, DataLayer_1.InteractionStep.DATES);
        setCurrentMonth(currentMonth.add(1, 'month'));
    };
    const setCalendarStyleAsMonth = () => {
        DataLayer_1.default.instance.sendInteraction('Set Calendar Style - Month', DataLayer_1.InteractionType.CALENDAR, DataLayer_1.InteractionStep.DATES);
        setCalendarStyle('Month');
    };
    const setCalendarStyleAsWeek = () => {
        DataLayer_1.default.instance.sendInteraction('Set Calendar Style - Week', DataLayer_1.InteractionType.CALENDAR, DataLayer_1.InteractionStep.DATES);
        setCalendarStyle('Week');
    };
    (0, react_1.useEffect)(() => {
        if (props.selectedStartDate && props.selectedEndDate && !nightStayValidation.init) {
            getLastValidDay(props.selectedStartDate, props.selectedEndDate, roomCode, rateCode).then((result) => {
                setNightStayValidation(result.nightStayValidation);
            });
        }
    }, [props.selectedStartDate, props.selectedEndDate]);
    (0, react_1.useEffect)(() => {
        if (props.selectedStartDate) {
            getArrivalNightStay(props.selectedStartDate, roomCode, rateCode).then((result) => {
                setArrivalNightStay(result);
            });
        }
    }, [props.selectedStartDate]);
    return (react_1.default.createElement(contexts_1.DatePickerContext.Provider, { value: context },
        react_1.default.createElement("div", { ref: firstUpdate, className: calendarClassNames },
            calendarStyle === 'Month' && (react_1.default.createElement("div", { className: "diji-calendar-navigation" },
                react_1.default.createElement(Icon_1.default, { icon: Icon_1.IconType.ArrowLeft2, onClick: previousMonthOnClick, color: Color_1.Color.White, backgroundColor: Color_1.Color.Navy, borderRadius: "round", size: "24px" }),
                react_1.default.createElement(Icon_1.default, { icon: Icon_1.IconType.ArrowRight2, onClick: nextMonthOnClick, color: Color_1.Color.White, backgroundColor: Color_1.Color.Navy, borderRadius: "round", size: "24px" }))),
            props.supportsWeek && (react_1.default.createElement("div", { className: "diji-calendar-picker-type" },
                react_1.default.createElement(Icon_1.default, { name: "Calendar_MothViewButton", icon: Icon_1.IconType.ViewMonth, size: "32px", color: calendarStyle === 'Month' ? Color_1.Color.Navy : Color_1.Color.Grey, onClick: setCalendarStyleAsMonth }),
                react_1.default.createElement(Icon_1.default, { name: "Calendar_WeekViewButton", icon: Icon_1.IconType.ViewWeek, size: "32px", color: calendarStyle === 'Week' ? Color_1.Color.Navy : Color_1.Color.Grey, onClick: setCalendarStyleAsWeek }))),
            printMonths,
            props.showMinNightStay && props.showMultipleMonths && (react_1.default.createElement("div", { className: "diji-calendar--min-night-stay u-flex u-flex-direction-column u-flex-align-center" },
                react_1.default.createElement(DaysSelectedInformer_1.default, null),
                react_1.default.createElement(MinimumNightStayPill_1.default, null),
                react_1.default.createElement(CalendarHighlightLegend_1.default, { showMultipleMonths: props.showMultipleMonths })))),
        props.showMinNightStay && !props.showMultipleMonths && (react_1.default.createElement("div", { className: "diji-calendar--min-night-stay --small u-flex u-flex-direction-column u-flex-align-center u-marg-top" },
            react_1.default.createElement(DaysSelectedInformer_1.default, null),
            react_1.default.createElement(MinimumNightStayPill_1.default, null),
            react_1.default.createElement(CalendarHighlightLegend_1.default, { showMultipleMonths: props.showMultipleMonths })))));
}
//# sourceMappingURL=DatePicker.js.map