import * as React from 'react';
import OverlayTrigger from '../OverlayTrigger';
import { useCallback, useEffect, useRef, useState } from 'react';
import useProperty from '../utils/useProperty';
import FieldWrap from '../FieldWrap';
import SimpleButton from '../SimpleButton';
import { Flex } from 'rebass';
import { DateFormatter } from '../../Utilities/Helpers/FormatHelper';
import { useDatepickerContext } from './DatepickerContext';
import { DayPicker } from 'react-day-picker';
import { AdaptableDateInlineInput } from '../../View/Components/AdaptableInput/AdaptableDateInlineInput';
import { isValid, addYears, endOfYear, startOfYear, addDays, addBusinessDays, } from 'date-fns';
import { Select } from '../Select';
const onDatePickerDropdownKeyDown = (e) => {
    if (e.key === 'Escape' || e.key === 'Enter') {
        e.stopPropagation();
    }
};
const DatePickerComponents = {
    YearsDropdown: (props) => {
        const onChange = useCallback((value) => {
            props.onChange?.({
                target: {
                    value,
                },
            });
        }, [props.onChange]);
        return (React.createElement(Select, { onKeyDown: onDatePickerDropdownKeyDown, value: props.value, onChange: onChange, options: props.options }));
    },
    MonthsDropdown: (props) => {
        const onChange = useCallback((value) => {
            props.onChange?.({
                target: {
                    value,
                },
            });
        }, [props.onChange]);
        return (React.createElement(Select, { onKeyDown: onDatePickerDropdownKeyDown, value: `${props.value}`, onChange: onChange, options: props.options.map((option) => {
                return {
                    label: option.label,
                    value: `${option.value}`,
                };
            }) }));
    },
};
const DatepickerOverlay = ({ onHide, children, onKeyDown, onMouseDown, overlayDOMRef, }) => {
    const domRef = React.useRef(null);
    return (React.createElement("div", { className: "ab-Datepicker-Overlay", tabIndex: -1, ref: (el) => {
            domRef.current = el;
            overlayDOMRef.current = el;
        }, onKeyDown: onKeyDown, onMouseDown: onMouseDown, onBlur: (e) => {
            const { relatedTarget } = e;
            const node = domRef.current;
            // relatedTarget is the newly focused element as a result of this blur event
            // so we close the overlay when the newly focused element is outside the overlay
            if (relatedTarget == null || !node.contains?.(relatedTarget)) {
                onHide();
            }
        } }, children));
};
const END_MONTH = endOfYear(addYears(new Date(), 10));
const START_MONTH = startOfYear(addYears(new Date(), -50));
export const Datepicker = React.forwardRef((props, ref) => {
    const { dateProps, required, disabled, style, placeholder, showWeekNumber, showOutsideDays, value: _, defaultValue: __, onChange: ___, datepickerButtons, showClearButton, autoFocus, ...boxProps } = props;
    const datepickerContext = useDatepickerContext();
    let [value, setValue] = useProperty(props, 'value', undefined, {
        onChange: props.onChange,
    });
    useEffect(() => {
        // when value is reset, also reset the month to the current month
        if (!value) {
            setMonth(new Date());
        }
    }, [!!value]);
    const [month, setMonth] = useState(value ?? new Date());
    const updateValue = (value) => {
        setValue(value);
        setMonth(value ?? new Date());
    };
    const inputValue = DateFormatter(value, { Pattern: dateProps.format }) ?? '';
    const [visible, doSetVisible] = useState(false);
    const setVisible = (visible, keyboardEventKey) => {
        doSetVisible(visible);
        if (!visible) {
            datepickerContext?.onHide?.(keyboardEventKey);
        }
        else {
            datepickerContext?.onShow?.();
        }
    };
    const clearValue = () => {
        updateValue(undefined);
    };
    const renderButton = (label, onClick) => (React.createElement(SimpleButton, { onClick: onClick, margin: '2px' }, label));
    const todayDate = new Date();
    const footerButtonsMap = {
        clear: renderButton('Clear', () => clearValue()),
        close: renderButton('Close', () => setVisible(false)),
        today: renderButton('Today', () => updateValue(todayDate)),
        tomorrow: renderButton('Tomorrow', () => updateValue(addDays(todayDate, 1))),
        yesterday: renderButton('Yesterday', () => updateValue(addDays(todayDate, -1))),
        nextWorkday: renderButton('Next Workday', () => updateValue(addBusinessDays(todayDate, 1))),
        prevWorkday: renderButton('Prev Workday', () => updateValue(addBusinessDays(todayDate, -1))),
        '-': React.createElement("div", { style: { flex: '1 1 1%' } }),
        '|': React.createElement("hr", { style: { width: '100%', height: 0, margin: 0, border: 'none' } }),
    };
    const footerButtons = datepickerButtons.map((buttonKey, index) => React.cloneElement(footerButtonsMap[buttonKey], { key: index }));
    const clearButton = showClearButton !== false ? (React.createElement(SimpleButton, { "data-name": "clear", variant: "text", tooltip: "Clear", iconSize: 20, padding: 0, icon: "close", onMouseDown: (e) => {
            e.preventDefault();
            clearValue();
        }, accessLevel: 'Full' })) : null;
    const calendarButton = (React.createElement(SimpleButton, { disabled: disabled, variant: "text", icon: "calendar", tooltip: "Date", iconSize: 20, px: 0, py: 0, onClick: () => setVisible(true) }));
    const overlayDOMRef = useRef(null);
    return (React.createElement(Flex, null,
        React.createElement(OverlayTrigger, { visible: visible, render: () => (React.createElement(DatepickerOverlay, { overlayDOMRef: overlayDOMRef, onMouseDown: props.onMouseDown, onHide: () => setVisible(false), onKeyDown: (e) => {
                    if (e.key === 'Escape' || e.key === 'Enter') {
                        setVisible(false, e.key);
                    }
                } },
                React.createElement(DayPicker, { fixedWeeks: true, autoFocus: autoFocus ?? true, showWeekNumber: showWeekNumber, showOutsideDays: showOutsideDays, mode: "single", captionLayout: "dropdown", month: isNaN(+month) ? new Date() : month, selected: value, onMonthChange: setMonth, onSelect: updateValue, startMonth: START_MONTH, endMonth: END_MONTH, components: DatePickerComponents, footer: React.createElement(Flex, { justifyContent: "space-between", mt: 2, flexWrap: 'wrap' }, footerButtons) }))) },
            React.createElement(FieldWrap, { ...boxProps, style: {
                    borderRadius: style?.borderRadius,
                    width: style?.width,
                    maxWidth: style?.maxWidth,
                    border: style?.border,
                }, className: "ab-Datepicker", onFocus: () => {
                    if (!visible) {
                        setVisible(true);
                    }
                }, onBlur: (e) => {
                    const { relatedTarget } = e;
                    const overlayDOMNode = overlayDOMRef.current;
                    if ((overlayDOMNode && relatedTarget == overlayDOMNode) ||
                        overlayDOMNode?.contains(relatedTarget)) {
                        return;
                    }
                    setVisible(false);
                } },
                React.createElement(AdaptableDateInlineInput, { ref: ref, value: inputValue, 
                    // We do not want to show the format when the date-picker is visible
                    placeholder: placeholder ?? '', onChange: (value) => {
                        const date = new Date(value);
                        if (isValid(date)) {
                            updateValue(date);
                        }
                    }, style: style, disabled: disabled }),
                !!inputValue ? clearButton : null,
                calendarButton))));
});
