import React__default, { useState, useRef, useEffect } from 'react';
import { useKeyPress } from '../../../../hooks/useKeyPress.js';
import { getDays, getIsSameDay, getIsToday, getMonthName, isInDateRange } from '../../dateUtils.js';
import { Day } from '../day/index.js';
import { DayNameRow } from '../dayNameRow/index.js';
import { CalendarWrapper, NarrowMonth, Dates } from './styles.js';
import { getStartColumn, getAllDays, getIndexFromGridPosition, getGridPosition, getDayWidth, hasEndRange, isDisabled } from './utils.js';

function Calendar(props) {
    const [days, setDays] = useState([]);
    const [startDay, setStartDay] = useState(0);
    const calendarRef = useRef(null);
    const startColumn = getStartColumn(props.startingDay, startDay, props.selection);
    const focusRef = useRef(null);
    const arrowDownPressed = useKeyPress('ArrowDown', focusRef);
    const arrowUpPressed = useKeyPress('ArrowUp', focusRef);
    const arrowLeftPressed = useKeyPress('ArrowLeft', focusRef);
    const arrowRightPressed = useKeyPress('ArrowRight', focusRef);
    const enterPressed = useKeyPress('Enter', focusRef);
    const spacePressed = useKeyPress('Space', focusRef);
    const [isInitial, setIsInitial] = useState(true);
    const gridRef = useRef(null);
    const [gridPosition, setGridPosition] = useState({
        col: 0,
        row: 0,
    });
    const [arrowUpFlag, setArrowUpFlag] = useState(false);
    const [arrowDownFlag, setArrowDownFlag] = useState(false);
    useEffect(() => {
        if (props.visible) {
            setIsInitial(true);
        }
    }, [props.visible]);
    useEffect(() => {
        if (arrowUpPressed &&
            props.focusElementIndex !== null &&
            props.focusElementIndex) {
            if (props.focusElementIndex - 7 < 0) {
                if (props.selection === 'range') {
                    if (props.value === 'primary') {
                        props.handlePrevMonth && props.handlePrevMonth();
                    }
                    props.setCalenderWithFocus &&
                        props.value &&
                        props.setCalenderWithFocus('primary', props.value);
                }
                else {
                    setArrowUpFlag(true);
                    props.handlePrevMonth && props.handlePrevMonth();
                }
            }
            else {
                props.setFocusElementIndex &&
                    props.setFocusElementIndex(props.focusElementIndex - 7);
            }
        }
    }, [arrowUpPressed]);
    useEffect(() => {
        if (arrowDownPressed &&
            props.focusElementIndex !== null &&
            props.focusElementIndex) {
            if (props.focusElementIndex + 7 >= days.length) {
                if (props.selection === 'range') {
                    if (props.value === 'secondary') {
                        props.handleNextMonth && props.handleNextMonth();
                    }
                    props.setCalenderWithFocus &&
                        props.value &&
                        props.setCalenderWithFocus('secondary', props.value);
                }
                else {
                    props.handleNextMonth && props.handleNextMonth();
                    setArrowDownFlag(true);
                }
            }
            else {
                props.setFocusElementIndex &&
                    props.setFocusElementIndex(props.focusElementIndex + 7);
            }
        }
    }, [arrowDownPressed]);
    useEffect(() => {
        if (arrowLeftPressed &&
            props.focusElementIndex !== null &&
            props.focusElementIndex) {
            if (props.focusElementIndex === 0) {
                if (props.selection === 'range') {
                    if (props.value === 'primary') {
                        props.handlePrevMonth && props.handlePrevMonth();
                    }
                    props.setCalenderWithFocus &&
                        props.value &&
                        props.setCalenderWithFocus('primary', props.value);
                }
                else {
                    props.handlePrevMonth && props.handlePrevMonth();
                    setArrowUpFlag(true);
                }
            }
            else {
                props.setFocusElementIndex &&
                    props.setFocusElementIndex(props.focusElementIndex - 1);
            }
        }
    }, [arrowLeftPressed]);
    useEffect(() => {
        if (arrowRightPressed &&
            props.focusElementIndex !== null &&
            props.focusElementIndex) {
            if (props.focusElementIndex === days.length - 1) {
                if (props.selection === 'range') {
                    if (props.value === 'secondary') {
                        props.handleNextMonth && props.handleNextMonth();
                    }
                    props.setCalenderWithFocus &&
                        props.value &&
                        props.setCalenderWithFocus('secondary', props.value);
                }
                else {
                    props.handleNextMonth && props.handleNextMonth();
                    setArrowDownFlag(true);
                }
            }
            else {
                props.setFocusElementIndex &&
                    props.setFocusElementIndex(props.focusElementIndex + 1);
            }
        }
    }, [arrowRightPressed]);
    useEffect(() => {
        if (enterPressed || spacePressed) {
            const date = props.focusElementIndex
                ? days[props.focusElementIndex]
                : days[0];
            props.handleChange(date);
            if (date.getMonth() !== props.month) {
                setIsInitial(true);
            }
        }
    }, [enterPressed, spacePressed]);
    useEffect(() => {
        const days = getDays(props.month, props.year);
        const startColumn = new Date(props.year, props.month).getDay();
        if (props.selection === 'single-date') {
            const allDays = getAllDays(startColumn, props.month, props.year, props.startingDay);
            setDays(allDays);
            setStartDay(0);
        }
        else {
            setDays(days);
            setStartDay(startColumn || 0);
        }
    }, [props.month, props.year, props.startingDay, props.selection]);
    useEffect(() => {
        if (focusRef.current) {
            focusRef.current.focus();
        }
    }, [props.focusElementIndex]);
    useEffect(() => {
        var _a;
        (_a = props.setLength) === null || _a === void 0 ? void 0 : _a.call(props, days.length);
    }, [days]);
    useEffect(() => {
        if (isInitial && days.length > 0 && props.hasFocus) {
            const focusStartIndex = days.findIndex((date) => props.selectedRange && getIsSameDay(date, props.selectedRange.start));
            // If there is a selected range, we set the start to have focus when the datepicker is opened
            if (focusStartIndex !== -1) {
                props.setFocusElementIndex &&
                    props.setFocusElementIndex(focusStartIndex);
            }
            else if (days.findIndex((date) => getIsToday(date)) !== -1) {
                // If there is no selected range, we set the today to have focus when the datepicker is opened
                const focusTodayIndex = days.findIndex((date) => getIsToday(date));
                props.setFocusElementIndex &&
                    props.setFocusElementIndex(focusTodayIndex);
            }
            else {
                const index = days.findIndex((date) => date.getDate() === 1);
                props.setFocusElementIndex && props.setFocusElementIndex(index);
            }
            setIsInitial(false);
        }
    }, [days.length, props.hasFocus, isInitial]);
    // This useEffect contains logic for the calender if we are only showing a single month at a time
    useEffect(() => {
        if (arrowUpFlag) {
            // Set the focus position on the previous month to be in the same column but in the last row
            props.setFocusElementIndex &&
                props.setFocusElementIndex(getIndexFromGridPosition({
                    row: gridPosition.row,
                    col: gridPosition.col,
                }));
            setArrowUpFlag(false);
        }
        else if (arrowDownFlag) {
            // Set the focus position on the next month to be in the same column but in the first row
            props.setFocusElementIndex &&
                props.setFocusElementIndex(getIndexFromGridPosition({ row: 0, col: gridPosition.col }));
            setArrowDownFlag(false);
        }
    }, [arrowDownFlag, arrowUpFlag]);
    useEffect(() => {
        if (props.focusElementIndex) {
            const index = () => {
                if (props.focusElementIndex) {
                    return props.focusElementIndex;
                }
                return 0;
            };
            const p = getGridPosition(index(), gridRef);
            p && setGridPosition(p);
        }
    }, [props.focusElementIndex]);
    return (React__default.createElement(CalendarWrapper, { ref: calendarRef },
        props.startingDay !== 'none' &&
            (props.narrow ? (React__default.createElement(NarrowMonth, null, `${getMonthName(props.month, props.locale)} ${props.year}`)) : (React__default.createElement(DayNameRow, { startingDay: props.startingDay, narrow: props.narrow, locale: props.locale }))),
        React__default.createElement("div", null,
            React__default.createElement(Dates, { startColumn: startColumn, role: "grid", ref: gridRef }, days.map((day, index) => {
                return (React__default.createElement(Day, { ref: index === props.focusElementIndex ? focusRef : null, key: day.getDay() + index, selectedRange: props.selectedRange, day: day, width: getDayWidth(calendarRef), currentMonth: props.month, selection: props.selection, hasFocus: index === props.focusElementIndex, isStartDay: props.selectedRange
                        ? getIsSameDay(day, props.selectedRange.start)
                        : false, isEndDay: hasEndRange(day, props.selectedRange), isInRange: props.selectedRange && isInDateRange(props.selectedRange, day)
                        ? true
                        : false, hasEvent: props.eventDates
                        ? props.eventDates.some((e) => getIsSameDay(e.date, day))
                        : false, disabled: isDisabled(day, props.minDate, props.maxDate), onChange: props.handleChange }));
            })))));
}

export { Calendar };
