import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useEffect, useState, useRef, forwardRef } from 'react';
import ReactDOM from 'react-dom';
import { DayPicker } from 'react-day-picker';
import { startOfDay } from 'date-fns';
import { format, toZonedTime } from 'date-fns-tz';
import TimePicker from './Timepicker';
import Icon from '../Icon';
import './DatePicker.scss';
import Button from '../Button';
import Typography from '../Typography';
import classNames from 'classnames';
import { useMergeRefs } from '../../hooks/useMergeRefs';
const CustomDatePicker = forwardRef(({ minDate, maxDate, value, onChange, placeholder = 'Select a date', disabled = false, dateFormat = 'EEEE, dd MMM yyyy', calendarWidth, timezone = 'Asia/Kolkata', timeFormat = 'hh:mm a', error, helperText = '', dateOnly = false, className, zIndex = 10, isFilterDatePicker = false, isSelectableDate = false, onBlur, withOutDateFormat = false, }, ref) => {
    const [timeValue, setTimeValue] = useState('');
    const [selectedDate, setSelectedDate] = useState();
    const [isPickerOpen, setIsPickerOpen] = useState(false);
    const [timeError, setTimeError] = useState(false);
    const [selectedMonth, setSelectedMonth] = useState(new Date());
    const [view, setView] = useState('days');
    const [positionStyles, setPositionStyles] = useState({ top: null, left: null });
    const selectedDateRef = useRef(undefined);
    const [startYear, setStartYear] = useState(() => {
        const currentYear = selectedMonth?.getFullYear() ?? new Date().getFullYear();
        return currentYear - (currentYear % 12); // Set to the first year in the 12-year range
    });
    const pickerRef = useRef(null); // Ref to track the picker
    const containerRef = useRef(null);
    const mergedRef = useMergeRefs(pickerRef, ref);
    const todayInTimeZone = startOfDay(toZonedTime(new Date(), timezone));
    const systemTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
    useEffect(() => {
        selectedDateRef.current = selectedDate;
    }, [selectedDate]);
    useEffect(() => {
        if (value) {
            setTimeValue(formatTimeStr(value));
        }
        setSelectedDate(value);
    }, [value, isPickerOpen]);
    const formatTimeStr = (date) => {
        const hours = date.getHours().toString().padStart(2, '0');
        const minutes = date.getMinutes().toString().padStart(2, '0');
        return `${hours}:${minutes}`;
    };
    // Convert minDate and maxDate to "hh:mm" for the TimePicker if the dates match
    const minTime = selectedDate &&
        minDate &&
        selectedDate.toDateString() === minDate.toDateString()
        ? formatTimeStr(minDate)
        : undefined;
    const maxTime = selectedDate &&
        maxDate &&
        selectedDate.toDateString() === maxDate.toDateString()
        ? formatTimeStr(maxDate)
        : undefined;
    useEffect(() => {
        const adjustPosition = () => {
            if (containerRef.current) {
                const containerRect = containerRef.current.getBoundingClientRect();
                const spacing = 8;
                let top = containerRect.bottom + spacing;
                let left = containerRect.left;
                if (pickerRef.current) {
                    const pickerHeight = pickerRef.current.offsetHeight;
                    const pickerWidth = pickerRef.current.offsetWidth;
                    if (window.innerHeight - containerRect.bottom < pickerHeight) {
                        top = containerRect.top - pickerHeight - spacing;
                    }
                    if (window.innerWidth - containerRect.left < pickerWidth) {
                        left = containerRect.right - pickerWidth;
                    }
                }
                setPositionStyles({ top, left });
            }
        };
        if (isPickerOpen) {
            adjustPosition();
            setTimeout(() => { }, 200);
            window.addEventListener('resize', () => { });
        }
        return () => {
            window.removeEventListener('resize', adjustPosition);
        };
    }, [isPickerOpen]);
    const calendarStyle = {
        '--rdp-day-width': calendarWidth
            ? `${calendarWidth / 7 - 4}px`
            : undefined,
    };
    const handleTimeChange = (time) => {
        setTimeValue(time);
        if (selectedDate) {
            const [hoursStr, minutesStr] = time.split(':');
            const newSelectedDate = new Date(selectedDate);
            newSelectedDate.setHours(parseInt(hoursStr ? hoursStr : '0', 10));
            newSelectedDate.setMinutes(parseInt(minutesStr ? minutesStr : '0', 10) || 0);
            setSelectedDate(newSelectedDate);
        }
    };
    const handleDaySelect = (date) => {
        if (dateOnly) {
            if (!isSelectableDate || date) {
                setSelectedDate(date);
                if (withOutDateFormat && date) {
                    const formatted = format(date, dateFormat, {
                        timeZone: timezone,
                    });
                    onChange(date, formatted);
                }
                else {
                    onChange(date);
                }
            }
            resetAndCloseDatePicker();
        }
        else {
            if (!timeValue || !date) {
                // if need to set time to current time in case no time selected
                const now = new Date();
                date?.setHours(now.getHours(), now.getMinutes(), now.getSeconds());
                setSelectedDate(date);
            }
            else {
                const [hoursStr, minutesStr] = timeValue.split(':');
                date.setHours(parseInt(hoursStr ? hoursStr : '0', 10) || 0);
                date.setMinutes(parseInt(minutesStr ? minutesStr : '0', 10) || 0);
                setSelectedDate(date);
            }
        }
    };
    const handleSave = () => {
        if (selectedDateRef.current) {
            if (withOutDateFormat) {
                const formatted = format(selectedDateRef.current, dateFormat, {
                    timeZone: timezone,
                });
                onChange(selectedDateRef.current, formatted);
            }
            else {
                onChange(selectedDateRef.current);
            }
        }
        resetAndCloseDatePicker();
    };
    const handleDateInputClick = () => {
        setIsPickerOpen((prev) => !prev);
        setView('days');
        setSelectedMonth(value ?? new Date());
    };
    const handleClickOutside = (event) => {
        if (pickerRef.current &&
            !pickerRef.current.contains(event.target)) {
            if (onBlur) {
                onBlur(value);
            }
            resetAndCloseDatePicker();
        }
    };
    const handleCancel = () => {
        resetAndCloseDatePicker();
    };
    const resetAndCloseDatePicker = () => {
        setIsPickerOpen(false); // Close the picker if the click was outside
        setView('days'); // Return to default day view on close of day picker
        setSelectedMonth(value ?? new Date());
    };
    useEffect(() => {
        if (isPickerOpen) {
            document.addEventListener('mousedown', handleClickOutside);
        }
        else {
            document.removeEventListener('mousedown', handleClickOutside);
        }
        return () => {
            document.removeEventListener('mousedown', handleClickOutside); // Clean up the event listener
        };
    }, [isPickerOpen]);
    const months = Array.from({ length: 12 }, (_, i) => new Date(0, i).toLocaleString('default', { month: 'long' }));
    const years = Array.from({ length: 12 }, (_, i) => startYear + i);
    const handleMonthClick = () => setView('months');
    const handleYearClick = () => setView('years');
    const handleMonthSelect = (monthIndex) => {
        const newDate = new Date(selectedMonth || '');
        newDate.setMonth(monthIndex);
        setSelectedMonth(newDate);
        setView('days');
    };
    const handleYearSelect = (year) => {
        const newDate = new Date(selectedMonth || '');
        newDate.setFullYear(year);
        setSelectedMonth(newDate);
        setView('days');
    };
    const handleNextClick = () => {
        if (view === 'years') {
            setStartYear((prev) => prev + 12);
        }
    };
    const handlePrevClick = () => {
        if (view === 'years') {
            setStartYear((prev) => prev - 12);
        }
    };
    const isDisabledDate = (year, month, minDate, maxDate) => {
        const isMinDateValid = minDate instanceof Date && !isNaN(minDate.getTime());
        const isMaxDateValid = maxDate instanceof Date && !isNaN(maxDate.getTime());
        if (isMinDateValid) {
            if (year !== null && year < minDate.getFullYear())
                return true;
            if (year !== null &&
                month !== null &&
                year === minDate.getFullYear() &&
                month < minDate.getMonth())
                return true;
        }
        if (isMaxDateValid) {
            if (year !== null && year > maxDate.getFullYear())
                return true;
            if (year !== null &&
                month !== null &&
                year === maxDate.getFullYear() &&
                month > maxDate.getMonth())
                return true;
        }
        return false;
    };
    useEffect(() => {
        if (isPickerOpen && view === 'years') {
            const currentYear = selectedMonth?.getFullYear() ?? new Date().getFullYear();
            setStartYear(currentYear - (currentYear % 12)); // Reset to the first year in the range that contains the selected year
        }
    }, [isPickerOpen, selectedMonth, view]);
    // Custom Caption Component
    const CustomCaption = ({ children }) => {
        // If children is a React node (like an element), render it directly
        if (React.isValidElement(children)) {
            return _jsx("div", { children: children });
        }
        const [month = '', year = ''] = String(children).split(' ');
        return (_jsxs(Typography, { as: "div", fontWeight: "medium", lineHeight: "16.8px", className: "ff-calendar-haeder", children: [_jsx("span", { onClick: handleMonthClick, className: "ff-cursor-pointer", children: month }), _jsx("span", { onClick: handleYearClick, className: "ff-cursor-pointer", children: year })] }));
    };
    // Custom MonthGrid Component
    const CustomMonthGrid = () => {
        return (_jsx("div", { className: "ff-custom-month_grid", children: months.map((month, index) => {
                const isDisabled = isDisabledDate(selectedMonth?.getFullYear() || null, index, minDate, maxDate);
                return (_jsx("div", { onClick: () => !isDisabled && handleMonthSelect(index), className: classNames('ff-custom-month', {
                        'ff-custom-month--selected': index === selectedMonth?.getMonth(),
                        'ff-custom-month--disabled': isDisabled,
                    }), children: _jsx(Typography, { color: index === selectedMonth?.getMonth()
                            ? 'var(--primary-button-text-color)'
                            : undefined, children: month }) }, index));
            }) }));
    };
    const CustomPrevButton = ({ disabled, onClick, }) => {
        return (_jsx("button", { className: "ff-calendar-nav-button", onClick: onClick, disabled: disabled, children: _jsx(Icon, { name: "left_arrow_icon", height: 20, width: 20 }) }));
    };
    const CustomNextButton = ({ disabled, onClick, }) => {
        return (_jsx("button", { className: "ff-calendar-nav-button", onClick: onClick, disabled: disabled, children: _jsx(Icon, { name: "right_arrow_icon", height: 20, width: 20 }) }));
    };
    // Custom YearGrid Component
    const CustomYearGrid = () => {
        return (_jsx("div", { className: "ff-custom-year_grid", children: years.map((year) => {
                const isDisabled = isDisabledDate(year, null, minDate, maxDate);
                return (_jsx("div", { onClick: () => !isDisabled && handleYearSelect(year), className: classNames('ff-custom-year', {
                        'ff-custom-year--selected': year === selectedMonth?.getFullYear(),
                        'ff-custom-year--disabled': isDisabled,
                    }), children: _jsx(Typography, { color: year === selectedMonth?.getFullYear()
                            ? 'var(--primary-button-text-color)'
                            : undefined, children: year }) }, year));
            }) }));
    };
    return (_jsxs("div", { className: `ff-date-picker ${className}`, ref: containerRef, children: [_jsxs("div", { className: "ff-datepicker-input-container", children: [_jsxs("div", { className: "ff-input-with-icon ff-date-input-field", children: [_jsx(Icon, { name: 'calendar_icon', hoverEffect: false, className: "ff-calendar-icon" }), _jsx("input", { type: "text", value: value
                                    ? format(value, dateFormat, {
                                        timeZone: timezone,
                                    })
                                    : '', readOnly: true, placeholder: placeholder, className: isFilterDatePicker ? 'ff-filter-date-input' : 'ff-date-input', disabled: disabled, onClick: handleDateInputClick }), helperText && error && (_jsx("span", { className: classNames('ff-date-input-message', {
                                    'ff-date-input-message--danger': !!error,
                                }), children: helperText }))] }), !dateOnly && (_jsxs("div", { className: "ff-input-with-icon ff-time-input-field", children: [_jsx(Icon, { name: 'clock_icon', hoverEffect: false, className: "ff-clock-icon" }), _jsx("input", { type: "text", placeholder: "Select time", className: isFilterDatePicker ? 'ff-filter-time-input' : 'ff-time-input', value: value
                                    ? format(value, timeFormat, {
                                        timeZone: timezone,
                                    })
                                    : '', disabled: disabled, onClick: handleDateInputClick, readOnly: true })] }))] }), isPickerOpen &&
                !!top &&
                ReactDOM.createPortal(_jsxs("div", { className: "ff-date-picker-container", ref: mergedRef, style: {
                        zIndex,
                        top: `${positionStyles.top}px`,
                        left: `${positionStyles.left}px`,
                    }, children: [_jsxs("div", { className: "ff-calendar-container", children: [_jsx(DayPicker, { style: calendarStyle, className: "ff-calendar", mode: "single", selected: selectedDate, onSelect: handleDaySelect, month: selectedMonth, onMonthChange: (month) => {
                                        if (view === 'days') {
                                            setSelectedMonth(month);
                                        }
                                    }, onNextClick: handleNextClick, onPrevClick: handlePrevClick, modifiers: {
                                        today: todayInTimeZone,
                                    }, disableNavigation: view === 'months', disabled: [
                                        {
                                            before: new Date(minDate ? minDate : ''),
                                            after: new Date(maxDate ? maxDate : ''),
                                        },
                                    ], timeZone: systemTimeZone, components: {
                                        CaptionLabel: (props) => _jsx(CustomCaption, { ...props }),
                                        PreviousMonthButton: (props) => (_jsx(CustomPrevButton, { ...props })),
                                        NextMonthButton: (props) => _jsx(CustomNextButton, { ...props }),
                                        ...(view === 'months'
                                            ? {
                                                MonthGrid: () => _jsx(CustomMonthGrid, {}),
                                            }
                                            : {}),
                                        ...(view === 'years'
                                            ? {
                                                MonthGrid: () => _jsx(CustomYearGrid, {}),
                                            }
                                            : {}),
                                    } }), !dateOnly && (_jsx(TimePicker, { value: timeValue, onChange: handleTimeChange, minTime: minTime, maxTime: maxTime, onErrorChange: setTimeError }))] }), !dateOnly && (_jsxs("div", { className: "ff-date-picker-controls", children: [_jsx(Button, { className: "ff-date-picker-button", variant: "secondary", onClick: handleCancel, label: "Cancel" }), _jsx(Button, { className: "ff-date-picker-button", variant: "primary", onClick: handleSave, label: "Save", disabled: timeError })] }))] }), document.body)] }));
});
export default CustomDatePicker;
//# sourceMappingURL=DatePicker.js.map