import React__default, { useState, useRef, useEffect, useMemo } from 'react';
import { usePopper } from 'react-popper';
import { useOnClickOutside } from '../../hooks/useClickOutside.js';
import AlertCircle from '../../icons/AlertCircle.js';
import { getId } from '../../utils/index.js';
import { LabelWrapper, Label, SupportingText, ErrorMessage, AssistMessage } from '../Field/styles.js';
import { ActionButtons } from './components/actionButtons/index.js';
import { Calendar } from './components/calendar/index.js';
import { getNextMonth, getNextYear } from './components/calendar/utils.js';
import { DatePickerNarrow } from './components/datePickerNarrow/index.js';
import { Header } from './components/header/index.js';
import { Input } from './components/input/index.js';
import { Selectors, SelectorsOld } from './components/selectors/index.js';
import { getDaysInMonth, YEARS_TO_DISPLAY, getIsSameDay } from './dateUtils.js';
import { DatePickerWrapper, Wrapper, CalendarsWrapper } from './styles.js';
import { popperOptions, getSelectors, commonDateSelectors, shouldUseSelectorsProp, getCurrentMonth, CommonSelectorValue, prevMonth, year, JS_MONTHS } from './utils.js';
import { MonthAndYearSelectionHeader } from './components/monthAndYearSelectionHeader/index.js';
import { Month } from './components/month/index.js';
import { Year } from './components/year/index.js';

function DatePicker(props) {
    var _a, _b, _c, _d;
    const { variant, disabled = false, selection = 'single-date', dismissText = 'Dismiss', confirmText = 'Confirm', months = 1, startingDay = 'sunday', placeholder = 'Select Date', narrow = false, locale = 'en_CA', label, hasError = false, errorText, assistText, onBlur, touched, leadingIcon, getInputLabel, 'data-testid': dataTestId, 'data-trackid': dataTrackId, monthAndYearSelection = false, } = props;
    const date = new Date();
    const appendTestId = getId(dataTestId);
    const appendTrackId = getId(dataTrackId);
    const [prevSelectedSelector, setPrevSelectedSelector] = useState();
    const [selectedSelector, setSelectedSelector] = useState();
    const [highlightedRange, setHighlightedRange] = useState(null);
    const [currentYear, setCurrentYear] = useState(date.getFullYear());
    const [currentMonth, setCurrentMonth] = useState(0);
    const nextMonth = getNextMonth(currentMonth);
    const [visible, setVisibility] = useState(false);
    const [referenceElement, setReferenceElement] = useState(null);
    const [popperElement, setPopperElement] = useState(null);
    const { containerRef } = useOnClickOutside(onDismiss);
    const { styles, attributes } = usePopper(referenceElement, popperElement, popperOptions);
    const [calenderWithFocus, setCalenderWithFocus] = useState('primary');
    const [focusElementIndex, setFocusElementIndex] = useState(0);
    const [primaryLength, setPrimaryLength] = useState(0);
    const inputRef = useRef(null);
    const [showError, setShowError] = useState(false);
    const [viewType, setViewType] = useState('calendar');
    const [calendarWidth, setCalendarWidth] = useState(0);
    const [calendarHeight, setCalendarHeight] = useState(0);
    useEffect(() => {
        var _a, _b;
        if (viewType === 'calendar') {
            setCalendarWidth((_a = popperElement === null || popperElement === void 0 ? void 0 : popperElement.offsetWidth) !== null && _a !== void 0 ? _a : 0);
            setCalendarHeight((_b = popperElement === null || popperElement === void 0 ? void 0 : popperElement.offsetHeight) !== null && _b !== void 0 ? _b : 0);
        }
    }, [popperElement]);
    const selectors = useMemo(() => props.selectors
        ? getSelectors(props.selectors)
        : getSelectors(commonDateSelectors), [(_a = props.selectors) === null || _a === void 0 ? void 0 : _a.length]);
    const showSelectors = useMemo(() => props.showSelectors || shouldUseSelectorsProp(selectors), [selectors, props.showSelectors]);
    useEffect(() => {
        const composeError = typeof touched === 'undefined' ? hasError : hasError && touched;
        setShowError(composeError);
    }, [hasError, touched]);
    useEffect(() => {
        if (!visible) {
            setViewType('calendar');
        }
        const cur = getCurrentMonth(date, props.selectedRange);
        setCurrentMonth(cur);
        props.selectedRange &&
            setCurrentYear((props.selectedRange instanceof Date
                ? props.selectedRange
                : props.selectedRange.start).getFullYear());
        if (inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) {
            if (!visible) {
                inputRef.current.blur();
                onBlur === null || onBlur === void 0 ? void 0 : onBlur();
            }
        }
    }, [visible]);
    useEffect(() => {
        if (showSelectors) {
            setSelectedSelector(selectors.find((selector) => selector.value === CommonSelectorValue.custom));
        }
    }, [showSelectors]);
    useEffect(() => {
        var _a;
        if (showSelectors &&
            selectedSelector &&
            selectedSelector.value !== CommonSelectorValue.custom) {
            const { dateRange } = selectedSelector;
            if (dateRange) {
                const range = dateRange instanceof Date
                    ? { start: dateRange, end: dateRange }
                    : { start: dateRange.start, end: dateRange.end };
                setHighlightedRange(range);
                setCurrentMonth(range.start.getMonth());
                setCurrentYear(range.start.getFullYear());
                (_a = props.onSelect) === null || _a === void 0 ? void 0 : _a.call(props, range);
                if (selectedSelector.value === CommonSelectorValue.lastMonth) {
                    setCurrentMonth(prevMonth);
                    setCurrentYear(year);
                }
            }
        }
    }, [selectedSelector]);
    useEffect(() => {
        setFocusElementIndex(getDaysInMonth(currentMonth, currentYear));
    }, [currentMonth]);
    function handleNextMonth() {
        if (currentMonth === JS_MONTHS.December) {
            setCurrentMonth(0);
            setCurrentYear(currentYear + 1);
        }
        else {
            setCurrentMonth(currentMonth + 1);
        }
    }
    function handlePrevYear() {
        setCurrentYear(currentYear - YEARS_TO_DISPLAY);
    }
    function handleNextYear() {
        setCurrentYear(currentYear + YEARS_TO_DISPLAY);
    }
    function handlePrevMonth() {
        if (currentMonth <= JS_MONTHS.January) {
            setCurrentYear(currentYear - 1);
            setCurrentMonth(JS_MONTHS.December);
        }
        else {
            setCurrentMonth(currentMonth - 1);
        }
    }
    function handleRangeChange(date) {
        var _a, _b, _c, _d, _e;
        setSelectedSelector(selectors.find((selector) => selector.value === CommonSelectorValue.custom));
        if (selection === 'single-date') {
            if ((date.getMonth() > currentMonth && date.getFullYear() >= currentYear) ||
                (date.getMonth() === JS_MONTHS.January &&
                    currentMonth === JS_MONTHS.December)) {
                handleNextMonth();
            }
            if ((date.getMonth() < currentMonth && date.getFullYear() <= currentYear) ||
                (currentMonth === JS_MONTHS.January &&
                    date.getMonth() === JS_MONTHS.December)) {
                handlePrevMonth();
            }
        }
        if (props.selection === 'range') {
            if (!highlightedRange) {
                const range = { start: date, end: date };
                setHighlightedRange(range);
                (_a = props.onSelect) === null || _a === void 0 ? void 0 : _a.call(props, range);
            }
            if (highlightedRange) {
                if (date < highlightedRange.start) {
                    const range = { start: date, end: highlightedRange.start };
                    setHighlightedRange(range);
                    (_b = props.onSelect) === null || _b === void 0 ? void 0 : _b.call(props, range);
                }
                if (date >= highlightedRange.start) {
                    const range = Object.assign(Object.assign({}, highlightedRange), { end: date });
                    setHighlightedRange(range);
                    (_c = props.onSelect) === null || _c === void 0 ? void 0 : _c.call(props, range);
                }
                if (!getIsSameDay(highlightedRange.start, highlightedRange.end)) {
                    const range = { start: date, end: date };
                    setHighlightedRange(range);
                    (_d = props.onSelect) === null || _d === void 0 ? void 0 : _d.call(props, range);
                }
            }
        }
        else {
            const range = { start: date, end: date };
            setHighlightedRange(range);
            (_e = props.onSelect) === null || _e === void 0 ? void 0 : _e.call(props, range);
        }
    }
    function handleInputClick() {
        if (!disabled)
            setVisibility(true);
    }
    function onConfirm() {
        if (highlightedRange) {
            props.onChange(highlightedRange);
        }
        setVisibility(false);
        setPrevSelectedSelector(undefined);
    }
    function onDismiss() {
        setHighlightedRange(null);
        setVisibility(false);
        if (prevSelectedSelector) {
            setSelectedSelector(prevSelectedSelector);
            setPrevSelectedSelector(undefined);
        }
    }
    function handleSelectorChange(selector) {
        setSelectedSelector(selector);
        if (!prevSelectedSelector)
            setPrevSelectedSelector(selectedSelector);
    }
    function formatSelectedRange() {
        if (props.selectedRange instanceof Date) {
            return { start: props.selectedRange, end: props.selectedRange };
        }
        return props.selectedRange;
    }
    function handleCalenderFocusChange(calendar, prevCalender) {
        if (prevCalender === 'primary' && calendar === 'secondary') {
            setFocusElementIndex(0);
        }
        else if (prevCalender === 'secondary' && calendar === 'primary') {
            setFocusElementIndex(primaryLength - 1);
        }
        setCalenderWithFocus(calendar);
    }
    const updateCurrentMonth = (month) => {
        setViewType('calendar');
        setCurrentMonth(month);
    };
    const updateCurrentYear = (year) => {
        setViewType('calendar');
        setCurrentYear(year);
    };
    return (React__default.createElement(DatePickerWrapper, { "data-testid": appendTestId(), "data-trackid": appendTrackId() }, props.narrow ? (React__default.createElement(DatePickerNarrow, Object.assign({}, props, { disabled: disabled, selectors: selectors, showSelectors: !!props.showSelectors, selection: (_b = props.selection) !== null && _b !== void 0 ? _b : 'single-date', selectedRange: highlightedRange !== null && highlightedRange !== void 0 ? highlightedRange : formatSelectedRange(), customSelectors: props.customSelectors, defaultSelectorValues: props.defaultSelectorValues, selectedSelector: selectedSelector, variant: variant, month: currentMonth, year: currentYear, startingDay: startingDay, locale: locale, handleChange: handleRangeChange, dismissText: dismissText, confirmText: confirmText, onConfirm: onConfirm, onDismiss: onDismiss, onSelectorClick: handleSelectorChange, eventDates: props.eventDates, minDate: props.minDate, maxDate: props.maxDate, placeholder: props.placeholder, label: props.label }))) : (React__default.createElement("div", { ref: containerRef },
        React__default.createElement("div", { ref: setReferenceElement },
            label && (React__default.createElement(LabelWrapper, { disabled: disabled, hasLabel: Boolean(label) },
                React__default.createElement(Label, { "data-testid": appendTestId('label'), disabled: disabled }, label))),
            React__default.createElement("div", { ref: inputRef, "data-testid": appendTestId('wrapper') },
                React__default.createElement(Input, { value: formatSelectedRange(), variant: variant, placeholder: placeholder, visible: visible, disabled: disabled, locale: locale, handleClick: handleInputClick, "data-testid": appendTestId('input'), hasError: showError, leadingIcon: leadingIcon, getInputLabel: getInputLabel })),
            React__default.createElement(SupportingText, null,
                Boolean(errorText) && showError && !disabled && (React__default.createElement(ErrorMessage, { "data-testid": appendTestId('error') },
                    React__default.createElement(AlertCircle, { width: 20, height: 20 }),
                    errorText)),
                !showError &&
                    (typeof assistText === 'string' ? (React__default.createElement(AssistMessage, { "data-testid": appendTestId('message') }, assistText)) : (assistText)))),
        visible && (React__default.createElement(Wrapper, Object.assign({ isVisible: visible, role: "dialog", "aria-modal": "true", "data-testid": appendTestId('dialog'), ref: setPopperElement, style: styles.popper }, attributes.popper),
            props.selectors && selection === 'range' && selectedSelector && (React__default.createElement(Selectors, { narrow: narrow, selectors: selectors, selectedSelector: selectedSelector, handleChange: handleSelectorChange, "data-testid": appendTestId('selectors') })),
            props.showSelectors &&
                selection === 'range' &&
                selectedSelector && (React__default.createElement(SelectorsOld, { narrow: narrow, defaultSelectorValues: props.defaultSelectorValues, customSelectors: props.customSelectors, selectedSelector: selectedSelector, handleChange: handleSelectorChange, "data-testid": appendTestId('selectors') })),
            React__default.createElement("div", null,
                monthAndYearSelection && selection !== 'range' ? (React__default.createElement(MonthAndYearSelectionHeader, { currentMonth: currentMonth, currentYear: currentYear, locale: locale, viewType: viewType, handleNextYear: handleNextYear, handlePrevYear: handlePrevYear, handleNextMonth: handleNextMonth, handlePrevMonth: handlePrevMonth, updateViewType: (viewType) => setViewType(viewType), "data-testid": appendTestId('month-and-year-selection-header'), minDate: props.minDate, maxDate: props.maxDate })) : (React__default.createElement(Header, { selection: selection, currentMonth: currentMonth, nextMonth: nextMonth, currentYear: currentYear, months: months, locale: locale, handleNextMonth: handleNextMonth, handlePrevMonth: handlePrevMonth, "data-testid": appendTestId('header') })),
                viewType === 'year' && (React__default.createElement(Year, { "data-testid": appendTestId('year-selection'), width: calendarWidth, height: calendarHeight, minimumYear: (_c = props.minDate) === null || _c === void 0 ? void 0 : _c.getFullYear(), maximumYear: (_d = props.maxDate) === null || _d === void 0 ? void 0 : _d.getFullYear(), currentYear: currentYear, updateCurrentYear: updateCurrentYear })),
                viewType === 'month' && (React__default.createElement(Month, { "data-testid": appendTestId('month-selection'), width: calendarWidth, height: calendarHeight, locale: locale, currentMonth: currentMonth, updateCurrentMonth: updateCurrentMonth })),
                viewType === 'calendar' && (React__default.createElement(React__default.Fragment, null,
                    React__default.createElement(CalendarsWrapper, { "data-testid": appendTestId('calendar') },
                        React__default.createElement(Calendar, { value: "primary", focusElementIndex: calenderWithFocus === 'primary'
                                ? focusElementIndex
                                : null, selection: selection, selectedRange: highlightedRange || formatSelectedRange(), month: currentMonth, year: currentYear, startingDay: startingDay, locale: locale, eventDates: props.eventDates, handleChange: handleRangeChange, minDate: props.minDate, maxDate: props.maxDate, showSelectors: showSelectors, visible: visible, handlePrevMonth: handlePrevMonth, handleNextMonth: selection === 'single-date'
                                ? handleNextMonth
                                : undefined, hasFocus: calenderWithFocus === 'primary', setCalenderWithFocus: handleCalenderFocusChange, setFocusElementIndex: setFocusElementIndex, setLength: setPrimaryLength }),
                        months === 2 && selection === 'range' && (React__default.createElement(Calendar, { value: "secondary", focusElementIndex: calenderWithFocus === 'secondary'
                                ? focusElementIndex
                                : null, selection: selection, selectedRange: highlightedRange || formatSelectedRange(), month: getNextMonth(currentMonth), year: getNextYear(currentMonth, currentYear), startingDay: startingDay, locale: locale, eventDates: props.eventDates, handleChange: handleRangeChange, minDate: props.minDate, maxDate: props.maxDate, showSelectors: showSelectors, visible: visible, handleNextMonth: handleNextMonth, hasFocus: calenderWithFocus === 'secondary', setCalenderWithFocus: handleCalenderFocusChange, setFocusElementIndex: setFocusElementIndex }))),
                    React__default.createElement(ActionButtons, { "data-testid": appendTestId('action-buttons'), dismissText: dismissText, confirmText: confirmText, onConfirm: onConfirm, onDismiss: onDismiss }))))))))));
}

export { DatePicker };
