// Tremor Date Picker [v2.0.0]

"use client";

import { Time } from "@internationalized/date";
import * as PopoverPrimitives from "@radix-ui/react-popover";
import {
    type AriaTimeFieldProps,
    type TimeValue,
    useDateSegment,
    useTimeField,
} from "@react-aria/datepicker";
import {
    type DateFieldState,
    type DateSegment,
    useTimeFieldState,
} from "@react-stately/datepicker";
import { RiCalendar2Fill, RiSubtractFill } from "@remixicon/react";
import { format, type Locale } from "date-fns";
import { enUS } from "date-fns/locale";
import * as React from "react";
import { tv, type VariantProps } from "tailwind-variants";

import { cx, focusInput, focusRing, hasErrorInput } from "@/tremor-lib/utils";

import { Button } from "./Button";
import { Calendar as CalendarPrimitive, type Matcher } from "./Calendar";

//#region TimeInput
// ============================================================================

const isBrowserLocaleClockType24h = () => {
    const language =
        typeof window !== "undefined" ? window.navigator.language : "en-US";

    const hr = new Intl.DateTimeFormat(language, {
        hour: "numeric",
    }).format();

    return Number.isInteger(Number(hr));
};

type TimeSegmentProps = {
    segment: DateSegment;
    state: DateFieldState;
};

const TimeSegment = ({ segment, state }: TimeSegmentProps) => {
    const ref = React.useRef<HTMLDivElement>(null);
    const { segmentProps } = useDateSegment(segment, state, ref);

    // Skip rendering for any non-editable segments except colon
    if (
        !segment.isEditable &&
        segment.type === "literal" &&
        segment.text !== ":"
    ) {
        return null;
    }

    return (
        <div
            {...segmentProps}
            ref={ref}
            className={cx(
                // base
                "relative block w-full appearance-none rounded-md border px-2.5 py-1.5 text-left uppercase tabular-nums shadow-xs outline-hidden transition sm:text-sm",
                // border color
                "border-gray-300 dark:border-gray-800",
                // text color
                "text-gray-900 dark:text-gray-50",
                // background color
                "bg-white dark:bg-gray-950",
                // focus
                focusInput,
                // invalid (optional)
                "group-aria-invalid/time-input:border-red-500 group-aria-invalid/time-input:ring-2 group-aria-invalid/time-input:ring-red-200 invalid:border-red-500 invalid:ring-2 invalid:ring-red-200 dark:group-aria-invalid/time-input:ring-red-400/20",
                {
                    "w-fit! border-none bg-transparent px-0 text-gray-400 shadow-none":
                        segment.type === "literal",
                    "border-gray-300 bg-gray-100 text-gray-400 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-500":
                        state.isDisabled && segment.text !== ":",
                },
            )}
        >
            {segment.isPlaceholder ? segment.placeholder : segment.text}
        </div>
    );
};

type TimeInputProps = Omit<
    AriaTimeFieldProps<TimeValue>,
    "label" | "shouldForceLeadingZeros" | "description" | "errorMessage"
>;

const TimeInput = React.forwardRef<HTMLDivElement, TimeInputProps>(
    ({ hourCycle, ...props }: TimeInputProps, ref) => {
        const innerRef = React.useRef<HTMLDivElement>(null);

        React.useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(
            ref,
            () => innerRef?.current,
        );

        const locale =
            window !== undefined ? window.navigator.language : "en-US";

        const state = useTimeFieldState({
            hourCycle: hourCycle,
            locale: locale,
            shouldForceLeadingZeros: true,
            autoFocus: true,
            ...props,
        });

        const { fieldProps } = useTimeField(
            {
                ...props,
                hourCycle: hourCycle,
                shouldForceLeadingZeros: true,
            },
            state,
            innerRef,
        );

        return (
            <div
                {...fieldProps}
                ref={innerRef}
                className="group/time-input inline-flex w-full gap-x-2"
            >
                {state.segments.map((segment, i) => (
                    // biome-ignore lint/suspicious/noArrayIndexKey: copied from Tremor site
                    <TimeSegment key={i} segment={segment} state={state} />
                ))}
            </div>
        );
    },
);
TimeInput.displayName = "TimeInput";

//#region Trigger
// ============================================================================

const triggerStyles = tv({
    base: [
        // base
        "peer flex w-full cursor-pointer appearance-none items-center gap-x-2 truncate rounded-md border px-3 py-2 shadow-xs outline-hidden transition-all sm:text-sm",
        // background color
        "bg-white dark:bg-gray-950",
        // border color
        "border-gray-300 dark:border-gray-800",
        // text color
        "text-gray-900 dark:text-gray-50",
        // placeholder color
        "placeholder-gray-400 dark:placeholder-gray-500",
        // hover
        "hover:bg-gray-50 dark:hover:bg-gray-950/50",
        // disabled
        "disabled:pointer-events-none",
        "disabled:bg-gray-100 disabled:text-gray-400",
        "dark:disabled:border-gray-800 dark:disabled:bg-gray-800 dark:disabled:text-gray-500",
        // focus
        focusInput,
        // invalid (optional)
        // "dark:aria-invalid:ring-red-400/20 aria-invalid:ring-2 aria-invalid:ring-red-200 aria-invalid:border-red-500 invalid:ring-2 invalid:ring-red-200 invalid:border-red-500"
    ],
    variants: {
        hasError: {
            true: hasErrorInput,
        },
    },
});

interface TriggerProps
    extends React.ComponentProps<"button">,
        VariantProps<typeof triggerStyles> {
    placeholder?: string;
}

const Trigger = React.forwardRef<HTMLButtonElement, TriggerProps>(
    (
        { className, children, placeholder, hasError, ...props }: TriggerProps,
        forwardedRef,
    ) => {
        return (
            <PopoverPrimitives.Trigger asChild>
                <button
                    ref={forwardedRef}
                    className={cx(triggerStyles({ hasError }), className)}
                    {...props}
                >
                    <RiCalendar2Fill className="size-5 shrink-0 text-gray-400 dark:text-gray-600" />
                    <span className="flex-1 overflow-hidden text-left text-ellipsis whitespace-nowrap text-gray-900 dark:text-gray-50">
                        {children ? (
                            children
                        ) : placeholder ? (
                            <span className="text-gray-400 dark:text-gray-600">
                                {placeholder}
                            </span>
                        ) : null}
                    </span>
                </button>
            </PopoverPrimitives.Trigger>
        );
    },
);

Trigger.displayName = "DatePicker.Trigger";

//#region Popover
// ============================================================================

const CalendarPopover = React.forwardRef<
    React.ElementRef<typeof PopoverPrimitives.Content>,
    React.ComponentProps<typeof PopoverPrimitives.Content>
>(({ align, className, children, ...props }, forwardedRef) => {
    return (
        <PopoverPrimitives.Portal>
            <PopoverPrimitives.Content
                ref={forwardedRef}
                sideOffset={10}
                side="bottom"
                align={align}
                avoidCollisions
                onOpenAutoFocus={(e) => e.preventDefault()}
                className={cx(
                    // base
                    "relative z-50 w-fit rounded-md border text-sm shadow-xl shadow-black/[2.5%]",
                    // widths
                    "max-w-[95vw] min-w-[calc(var(--radix-select-trigger-width)-2px)]",
                    // border color
                    "border-gray-200 dark:border-gray-800",
                    // background color
                    "bg-white dark:bg-gray-950",
                    // transition
                    "will-change-[transform,opacity]",
                    "data-[state=closed]:animate-hide",
                    "data-[state=open]:data-[side=bottom]:animate-slide-down-and-fade data-[state=open]:data-[side=left]:animate-slide-left-and-fade data-[state=open]:data-[side=right]:animate-slide-right-and-fade data-[state=open]:data-[side=top]:animate-slide-up-and-fade",
                    className,
                )}
                {...props}
            >
                {children}
            </PopoverPrimitives.Content>
        </PopoverPrimitives.Portal>
    );
});

CalendarPopover.displayName = "DatePicker.CalendarPopover";

//#region Preset
// ============================================================================

type DateRange = {
    from: Date | undefined;
    to?: Date | undefined;
};

interface Preset {
    label: string;
}

interface DatePreset extends Preset {
    date: Date;
}

interface DateRangePreset extends Preset {
    dateRange: DateRange;
}

type PresetContainerProps<TPreset extends Preset, TValue> = {
    presets: TPreset[];
    onSelect: (value: TValue) => void;
    currentValue?: TValue;
};

const PresetContainer = <TPreset extends Preset, TValue>({
    // Available preset configurations
    presets,
    // Event handler when a preset is selected
    onSelect,
    // Currently selected preset
    currentValue,
}: PresetContainerProps<TPreset, TValue>) => {
    // biome-ignore lint/suspicious/noExplicitAny: Type guard that handles value safely
    const isDateRangePresets = (preset: any): preset is DateRangePreset => {
        return "dateRange" in preset;
    };
    // biome-ignore lint/suspicious/noExplicitAny: Type guard that handles value safely
    const isDatePresets = (preset: any): preset is DatePreset => {
        return "date" in preset;
    };

    const handleClick = (preset: TPreset) => {
        if (isDateRangePresets(preset)) {
            onSelect(preset.dateRange as TValue);
        } else if (isDatePresets(preset)) {
            onSelect(preset.date as TValue);
        }
    };

    const compareDates = (date1: Date, date2: Date) => {
        return (
            date1.getDate() === date2.getDate() &&
            date1.getMonth() === date2.getMonth() &&
            date1.getFullYear() === date2.getFullYear()
        );
    };

    const compareRanges = (range1: DateRange, range2: DateRange) => {
        const from1 = range1.from;
        const from2 = range2.from;

        let equalFrom = false;

        if (from1 && from2) {
            const sameFrom = compareDates(from1, from2);

            if (sameFrom) {
                equalFrom = true;
            }
        }

        const to1 = range1.to;
        const to2 = range2.to;

        let equalTo = false;

        if (to1 && to2) {
            const sameTo = compareDates(to1, to2);

            if (sameTo) {
                equalTo = true;
            }
        }

        return equalFrom && equalTo;
    };

    const matchesCurrent = (preset: TPreset) => {
        if (isDateRangePresets(preset)) {
            const value = currentValue as DateRange | undefined;

            return value && compareRanges(value, preset.dateRange);
        }
        if (isDatePresets(preset)) {
            const value = currentValue as Date | undefined;

            return value && compareDates(value, preset.date);
        }

        return false;
    };

    return (
        <ul className="flex items-start gap-x-2 sm:flex-col">
            {presets.map((preset) => {
                return (
                    <li
                        key={`preset-${preset.label}`}
                        className="sm:w-full sm:py-px"
                    >
                        <button
                            type="button"
                            title={preset.label}
                            className={cx(
                                // base
                                "relative w-full overflow-hidden rounded-sm border px-2.5 py-1.5 text-left text-base text-ellipsis whitespace-nowrap shadow-xs outline-hidden transition-all sm:border-none sm:py-2 sm:text-sm sm:shadow-none",
                                // text color
                                "text-gray-700 dark:text-gray-300",
                                // border color
                                "border-gray-200 dark:border-gray-800",
                                // focus
                                focusRing,
                                // background color
                                "focus-visible:bg-gray-100 dark:focus-visible:bg-gray-900",
                                "hover:bg-gray-100 dark:hover:bg-gray-900",
                                {
                                    "bg-gray-100 dark:bg-gray-900":
                                        matchesCurrent(preset),
                                },
                            )}
                            onClick={() => handleClick(preset)}
                            aria-label={`Select ${preset.label}`}
                        >
                            <span>{preset.label}</span>
                        </button>
                    </li>
                );
            })}
        </ul>
    );
};

PresetContainer.displayName = "DatePicker.PresetContainer";

//#region Date Picker Shared
// ============================================================================

const formatDate = (
    date: Date,
    locale: Locale,
    includeTime?: boolean,
): string => {
    const usesAmPm = !isBrowserLocaleClockType24h();
    let dateString: string;

    if (includeTime) {
        dateString = usesAmPm
            ? format(date, "dd MMM, yyyy h:mm a", { locale })
            : format(date, "dd MMM, yyyy HH:mm", { locale });
    } else {
        dateString = format(date, "dd MMM, yyyy", { locale });
    }

    return dateString;
};

type CalendarProps = {
    fromYear?: number;
    toYear?: number;
    fromMonth?: Date;
    toMonth?: Date;
    fromDay?: Date;
    toDay?: Date;
    fromDate?: Date;
    toDate?: Date;
    locale?: Locale;
};

type Translations = {
    cancel?: string;
    apply?: string;
    start?: string;
    end?: string;
    range?: string;
};

interface PickerProps extends CalendarProps {
    className?: string;
    disabled?: boolean;
    disabledDays?: Matcher | Matcher[] | undefined;
    required?: boolean;
    showTimePicker?: boolean;
    placeholder?: string;
    enableYearNavigation?: boolean;
    disableNavigation?: boolean;
    hasError?: boolean;
    id?: string;
    // Customize the date picker for different languages.
    translations?: Translations;
    align?: "center" | "end" | "start";
    "aria-invalid"?: boolean;
    "aria-label"?: string;
    "aria-labelledby"?: string;
    "aria-required"?: boolean;
}

//#region Single Date Picker
// ============================================================================

interface SingleProps extends Omit<PickerProps, "translations"> {
    presets?: DatePreset[];
    defaultValue?: Date;
    value?: Date;
    onChange?: (date: Date | undefined) => void;
    translations?: Omit<Translations, "range">;
}

const SingleDatePicker = ({
    defaultValue,
    value,
    onChange,
    presets,
    disabled,
    disabledDays,
    disableNavigation,
    className,
    showTimePicker,
    placeholder = "Select date",
    hasError,
    translations,
    enableYearNavigation = false,
    locale = enUS,
    align = "center",
    ...props
}: SingleProps) => {
    const [open, setOpen] = React.useState(false);
    const [date, setDate] = React.useState<Date | undefined>(
        value ?? defaultValue ?? undefined,
    );
    const [month, setMonth] = React.useState<Date | undefined>(date);

    const [time, setTime] = React.useState<TimeValue | null>(
        value
            ? new Time(value.getHours(), value.getMinutes())
            : defaultValue
              ? new Time(defaultValue.getHours(), defaultValue.getMinutes())
              : new Time(0, 0),
    );

    // biome-ignore lint/correctness/useExhaustiveDependencies: copied from Tremor site
    const initialDate = React.useMemo(() => {
        return date;
    }, [open]);

    React.useEffect(() => {
        setDate(value ?? defaultValue ?? undefined);
    }, [value, defaultValue]);

    React.useEffect(() => {
        if (date) {
            setMonth(date);
        }
    }, [date]);

    // biome-ignore lint/correctness/useExhaustiveDependencies: copied from Tremor site
    React.useEffect(() => {
        if (!open) {
            setMonth(date);
        }
    }, [open]);

    const onCancel = () => {
        setDate(initialDate);
        setTime(
            initialDate
                ? new Time(initialDate.getHours(), initialDate.getMinutes())
                : new Time(0, 0),
        );
        setOpen(false);
    };

    const onOpenChange = (open: boolean) => {
        if (!open) {
            onCancel();
        }

        setOpen(open);
    };

    const onDateChange = (date: Date | undefined) => {
        const newDate = date;
        if (showTimePicker) {
            if (newDate && !time) {
                setTime(new Time(0, 0));
            }
            if (newDate && time) {
                newDate.setHours(time.hour);
                newDate.setMinutes(time.minute);
            }
        }
        setDate(newDate);
    };

    const onTimeChange = (time: TimeValue | null) => {
        setTime(time);

        if (!date) {
            return;
        }

        const newDate = new Date(date.getTime());

        if (!time) {
            newDate.setHours(0);
            newDate.setMinutes(0);
        } else {
            newDate.setHours(time.hour);
            newDate.setMinutes(time.minute);
        }

        setDate(newDate);
    };

    const formattedDate = React.useMemo(() => {
        if (!date) {
            return null;
        }

        return formatDate(date, locale, showTimePicker);
    }, [date, locale, showTimePicker]);

    const onApply = () => {
        setOpen(false);
        onChange?.(date);
    };

    React.useEffect(() => {
        setDate(value ?? defaultValue ?? undefined);
        setTime(
            value
                ? new Time(value.getHours(), value.getMinutes())
                : defaultValue
                  ? new Time(defaultValue.getHours(), defaultValue.getMinutes())
                  : new Time(0, 0),
        );
    }, [value, defaultValue]);

    return (
        <PopoverPrimitives.Root
            tremor-id="tremor-raw"
            open={open}
            onOpenChange={onOpenChange}
        >
            <Trigger
                placeholder={placeholder}
                disabled={disabled}
                className={className}
                hasError={hasError}
                aria-required={props.required || props["aria-required"]}
                aria-invalid={props["aria-invalid"]}
                aria-label={props["aria-label"]}
                aria-labelledby={props["aria-labelledby"]}
            >
                {formattedDate}
            </Trigger>
            <CalendarPopover align={align}>
                <div className="flex">
                    <div className="flex flex-col sm:flex-row sm:items-start">
                        {presets && presets.length > 0 && (
                            <div
                                className={cx(
                                    "relative flex h-14 w-full items-center sm:h-full sm:w-40",
                                    "border-b border-gray-200 sm:border-r sm:border-b-0 dark:border-gray-800",
                                    "overflow-auto",
                                )}
                            >
                                <div className="absolute px-2 pr-2 sm:inset-0 sm:left-0 sm:py-2">
                                    <PresetContainer
                                        currentValue={date}
                                        presets={presets}
                                        onSelect={onDateChange}
                                    />
                                </div>
                            </div>
                        )}
                        <div>
                            <CalendarPrimitive
                                mode="single"
                                month={month}
                                onMonthChange={setMonth}
                                selected={date}
                                onSelect={onDateChange}
                                disabled={disabledDays}
                                locale={locale}
                                enableYearNavigation={enableYearNavigation}
                                disableNavigation={disableNavigation}
                                initialFocus
                                {...props}
                            />
                            {showTimePicker && (
                                <div className="border-t border-gray-200 p-3 dark:border-gray-800">
                                    <TimeInput
                                        aria-label="Time"
                                        onChange={onTimeChange}
                                        isDisabled={!date}
                                        value={time}
                                        isRequired={props.required}
                                    />
                                </div>
                            )}
                            <div className="flex items-center gap-x-2 border-t border-gray-200 p-3 dark:border-gray-800">
                                <Button
                                    variant="secondary"
                                    className="h-8 w-full"
                                    type="button"
                                    onClick={onCancel}
                                >
                                    {translations?.cancel ?? "Cancel"}
                                </Button>
                                <Button
                                    variant="primary"
                                    className="h-8 w-full"
                                    type="button"
                                    onClick={onApply}
                                >
                                    {translations?.apply ?? "Apply"}
                                </Button>
                            </div>
                        </div>
                    </div>
                </div>
            </CalendarPopover>
        </PopoverPrimitives.Root>
    );
};

//#region Range Date Picker
// ============================================================================

interface RangeProps extends PickerProps {
    presets?: DateRangePreset[];
    defaultValue?: DateRange;
    value?: DateRange;
    onChange?: (dateRange: DateRange | undefined) => void;
}

const RangeDatePicker = ({
    defaultValue,
    value,
    onChange,
    presets,
    disabled,
    disableNavigation,
    disabledDays,
    enableYearNavigation = false,
    locale = enUS,
    showTimePicker,
    placeholder = "Select date range",
    hasError,
    translations,
    align = "center",
    className,
    ...props
}: RangeProps) => {
    const [open, setOpen] = React.useState(false);
    const [range, setRange] = React.useState<DateRange | undefined>(
        value ?? defaultValue ?? undefined,
    );
    const [month, setMonth] = React.useState<Date | undefined>(range?.from);

    const [startTime, setStartTime] = React.useState<TimeValue | null>(
        value?.from
            ? new Time(value.from.getHours(), value.from.getMinutes())
            : defaultValue?.from
              ? new Time(
                    defaultValue.from.getHours(),
                    defaultValue.from.getMinutes(),
                )
              : new Time(0, 0),
    );
    const [endTime, setEndTime] = React.useState<TimeValue | null>(
        value?.to
            ? new Time(value.to.getHours(), value.to.getMinutes())
            : defaultValue?.to
              ? new Time(
                    defaultValue.to.getHours(),
                    defaultValue.to.getMinutes(),
                )
              : new Time(0, 0),
    );

    // biome-ignore lint/correctness/useExhaustiveDependencies: copied from Tremor site
    const initialRange = React.useMemo(() => {
        return range;
    }, [open]);

    React.useEffect(() => {
        setRange(value ?? defaultValue ?? undefined);
    }, [value, defaultValue]);

    React.useEffect(() => {
        if (range) {
            setMonth(range.from);
        }
    }, [range]);

    // biome-ignore lint/correctness/useExhaustiveDependencies: copied from Tremor site
    React.useEffect(() => {
        if (!open) {
            setMonth(range?.from);
        }
    }, [open]);

    const onRangeChange = (range: DateRange | undefined) => {
        const newRange = range;
        if (showTimePicker) {
            if (newRange?.from && !startTime) {
                setStartTime(new Time(0, 0));
            }

            if (newRange?.to && !endTime) {
                setEndTime(new Time(0, 0));
            }

            if (newRange?.from && startTime) {
                newRange.from.setHours(startTime.hour);
                newRange.from.setMinutes(startTime.minute);
            }

            if (newRange?.to && endTime) {
                newRange.to.setHours(endTime.hour);
                newRange.to.setMinutes(endTime.minute);
            }
        }

        setRange(newRange);
    };

    const onCancel = () => {
        setRange(initialRange);
        setStartTime(
            initialRange?.from
                ? new Time(
                      initialRange.from.getHours(),
                      initialRange.from.getMinutes(),
                  )
                : new Time(0, 0),
        );
        setEndTime(
            initialRange?.to
                ? new Time(
                      initialRange.to.getHours(),
                      initialRange.to.getMinutes(),
                  )
                : new Time(0, 0),
        );
        setOpen(false);
    };

    const onOpenChange = (open: boolean) => {
        if (!open) {
            onCancel();
        }

        setOpen(open);
    };

    const onTimeChange = (time: TimeValue | null, pos: "start" | "end") => {
        switch (pos) {
            case "start":
                setStartTime(time);
                break;
            case "end":
                setEndTime(time);
                break;
        }

        if (!range) {
            return;
        }

        if (pos === "start") {
            if (!range.from) {
                return;
            }

            const newDate = new Date(range.from.getTime());

            if (!time) {
                newDate.setHours(0);
                newDate.setMinutes(0);
            } else {
                newDate.setHours(time.hour);
                newDate.setMinutes(time.minute);
            }

            setRange({
                ...range,
                from: newDate,
            });
        }

        if (pos === "end") {
            if (!range.to) {
                return;
            }

            const newDate = new Date(range.to.getTime());

            if (!time) {
                newDate.setHours(0);
                newDate.setMinutes(0);
            } else {
                newDate.setHours(time.hour);
                newDate.setMinutes(time.minute);
            }

            setRange({
                ...range,
                to: newDate,
            });
        }
    };

    React.useEffect(() => {
        setRange(value ?? defaultValue ?? undefined);

        setStartTime(
            value?.from
                ? new Time(value.from.getHours(), value.from.getMinutes())
                : defaultValue?.from
                  ? new Time(
                        defaultValue.from.getHours(),
                        defaultValue.from.getMinutes(),
                    )
                  : new Time(0, 0),
        );
        setEndTime(
            value?.to
                ? new Time(value.to.getHours(), value.to.getMinutes())
                : defaultValue?.to
                  ? new Time(
                        defaultValue.to.getHours(),
                        defaultValue.to.getMinutes(),
                    )
                  : new Time(0, 0),
        );
    }, [value, defaultValue]);

    const displayRange = React.useMemo(() => {
        if (!range) {
            return null;
        }

        return `${
            range.from ? formatDate(range.from, locale, showTimePicker) : ""
        } - ${range.to ? formatDate(range.to, locale, showTimePicker) : ""}`;
    }, [range, locale, showTimePicker]);

    const onApply = () => {
        setOpen(false);
        onChange?.(range);
    };

    return (
        <PopoverPrimitives.Root
            tremor-id="tremor-raw"
            open={open}
            onOpenChange={onOpenChange}
        >
            <Trigger
                placeholder={placeholder}
                disabled={disabled}
                className={className}
                hasError={hasError}
                aria-required={props.required || props["aria-required"]}
                aria-invalid={props["aria-invalid"]}
                aria-label={props["aria-label"]}
                aria-labelledby={props["aria-labelledby"]}
            >
                {displayRange}
            </Trigger>
            <CalendarPopover align={align}>
                <div className="flex">
                    <div className="flex flex-col overflow-x-auto sm:flex-row sm:items-start">
                        {presets && presets.length > 0 && (
                            <div
                                className={cx(
                                    "relative flex h-16 w-full items-center sm:h-full sm:w-40",
                                    "border-b border-gray-200 sm:border-r sm:border-b-0 dark:border-gray-800",
                                    "overflow-auto",
                                )}
                            >
                                <div className="absolute px-3 sm:inset-0 sm:left-0 sm:p-2">
                                    <PresetContainer
                                        currentValue={range}
                                        presets={presets}
                                        onSelect={onRangeChange}
                                    />
                                </div>
                            </div>
                        )}
                        <div className="overflow-x-auto">
                            <CalendarPrimitive
                                mode="range"
                                selected={range}
                                onSelect={onRangeChange}
                                month={month}
                                onMonthChange={setMonth}
                                numberOfMonths={2}
                                disabled={disabledDays}
                                disableNavigation={disableNavigation}
                                enableYearNavigation={enableYearNavigation}
                                locale={locale}
                                initialFocus
                                classNames={{
                                    months: "flex flex-row divide-x divide-gray-200 dark:divide-gray-800 overflow-x-auto",
                                }}
                                {...props}
                            />
                            {showTimePicker && (
                                <div className="flex items-center justify-evenly gap-x-3 border-t border-gray-200 p-3 dark:border-gray-800">
                                    <div className="flex flex-1 items-center gap-x-2">
                                        <span className="dark:text-gray-30 text-gray-700">
                                            {translations?.start ?? "Start"}:
                                        </span>
                                        <TimeInput
                                            value={startTime}
                                            onChange={(v) =>
                                                onTimeChange(v, "start")
                                            }
                                            aria-label="Start date time"
                                            isDisabled={!range?.from}
                                            isRequired={props.required}
                                        />
                                    </div>
                                    <RiSubtractFill className="size-4 shrink-0 text-gray-400" />
                                    <div className="flex flex-1 items-center gap-x-2">
                                        <span className="dark:text-gray-30 text-gray-700">
                                            {translations?.end ?? "End"}:
                                        </span>
                                        <TimeInput
                                            value={endTime}
                                            onChange={(v) =>
                                                onTimeChange(v, "end")
                                            }
                                            aria-label="End date time"
                                            isDisabled={!range?.to}
                                            isRequired={props.required}
                                        />
                                    </div>
                                </div>
                            )}
                            <div className="border-t border-gray-200 p-3 sm:flex sm:items-center sm:justify-between dark:border-gray-800">
                                <p className="text-gray-900 tabular-nums dark:text-gray-50">
                                    <span className="text-gray-700 dark:text-gray-300">
                                        {translations?.range ?? "Range"}:
                                    </span>{" "}
                                    <span className="font-medium">
                                        {displayRange}
                                    </span>
                                </p>
                                <div className="mt-2 flex items-center gap-x-2 sm:mt-0">
                                    <Button
                                        variant="secondary"
                                        className="h-8 w-full sm:w-fit"
                                        type="button"
                                        onClick={onCancel}
                                    >
                                        {translations?.cancel ?? "Cancel"}
                                    </Button>
                                    <Button
                                        variant="primary"
                                        className="h-8 w-full sm:w-fit"
                                        type="button"
                                        onClick={onApply}
                                    >
                                        {translations?.apply ?? "Apply"}
                                    </Button>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </CalendarPopover>
        </PopoverPrimitives.Root>
    );
};

//#region Preset Validation
// ============================================================================

const validatePresets = (
    presets: DateRangePreset[] | DatePreset[],
    rules: PickerProps,
) => {
    const { toYear, fromYear, fromMonth, toMonth, fromDay, toDay } = rules;

    if (presets && presets.length > 0) {
        const fromYearToUse = fromYear;
        const toYearToUse = toYear;

        for (const preset of presets) {
            if ("date" in preset) {
                const presetYear = preset.date.getFullYear();

                if (fromYear && presetYear < fromYear) {
                    throw new Error(
                        `Preset ${preset.label} is before fromYear ${fromYearToUse}.`,
                    );
                }

                if (toYear && presetYear > toYear) {
                    throw new Error(
                        `Preset ${preset.label} is after toYear ${toYearToUse}.`,
                    );
                }

                if (fromMonth) {
                    const presetMonth = preset.date.getMonth();

                    if (presetMonth < fromMonth.getMonth()) {
                        throw new Error(
                            `Preset ${preset.label} is before fromMonth ${fromMonth}.`,
                        );
                    }
                }

                if (toMonth) {
                    const presetMonth = preset.date.getMonth();

                    if (presetMonth > toMonth.getMonth()) {
                        throw new Error(
                            `Preset ${preset.label} is after toMonth ${toMonth}.`,
                        );
                    }
                }

                if (fromDay) {
                    const presetDay = preset.date.getDate();

                    if (presetDay < fromDay.getDate()) {
                        throw new Error(
                            `Preset ${preset.label} is before fromDay ${fromDay}.`,
                        );
                    }
                }

                if (toDay) {
                    const presetDay = preset.date.getDate();

                    if (presetDay > toDay.getDate()) {
                        throw new Error(
                            `Preset ${preset.label} is after toDay ${format(
                                toDay,
                                "MMM dd, yyyy",
                            )}.`,
                        );
                    }
                }
            }

            if ("dateRange" in preset) {
                const presetFromYear = preset.dateRange.from?.getFullYear();
                const presetToYear = preset.dateRange.to?.getFullYear();

                if (presetFromYear && fromYear && presetFromYear < fromYear) {
                    throw new Error(
                        `Preset ${preset.label}'s 'from' is before fromYear ${fromYearToUse}.`,
                    );
                }

                if (presetToYear && toYear && presetToYear > toYear) {
                    throw new Error(
                        `Preset ${preset.label}'s 'to' is after toYear ${toYearToUse}.`,
                    );
                }

                if (fromMonth) {
                    const presetMonth = preset.dateRange.from?.getMonth();

                    if (presetMonth && presetMonth < fromMonth.getMonth()) {
                        throw new Error(
                            `Preset ${
                                preset.label
                            }'s 'from' is before fromMonth ${format(
                                fromMonth,
                                "MMM, yyyy",
                            )}.`,
                        );
                    }
                }

                if (toMonth) {
                    const presetMonth = preset.dateRange.to?.getMonth();

                    if (presetMonth && presetMonth > toMonth.getMonth()) {
                        throw new Error(
                            `Preset ${
                                preset.label
                            }'s 'to' is after toMonth ${format(
                                toMonth,
                                "MMM, yyyy",
                            )}.`,
                        );
                    }
                }

                if (fromDay) {
                    const presetDay = preset.dateRange.from?.getDate();

                    if (presetDay && presetDay < fromDay.getDate()) {
                        throw new Error(
                            `Preset ${
                                preset.dateRange.from
                            }'s 'from' is before fromDay ${format(
                                fromDay,
                                "MMM dd, yyyy",
                            )}.`,
                        );
                    }
                }

                if (toDay) {
                    const presetDay = preset.dateRange.to?.getDate();

                    if (presetDay && presetDay > toDay.getDate()) {
                        throw new Error(
                            `Preset ${
                                preset.label
                            }'s 'to' is after toDay ${format(
                                toDay,
                                "MMM dd, yyyy",
                            )}.`,
                        );
                    }
                }
            }
        }
    }
};

//#region Types & Exports
// ============================================================================

type SingleDatePickerProps = {
    presets?: DatePreset[];
    defaultValue?: Date;
    value?: Date;
    onChange?: (date: Date | undefined) => void;
} & PickerProps;

const DatePicker = ({ presets, ...props }: SingleDatePickerProps) => {
    if (presets) {
        validatePresets(presets, props);
    }

    return <SingleDatePicker presets={presets} {...(props as SingleProps)} />;
};

DatePicker.displayName = "DatePicker";

type RangeDatePickerProps = {
    presets?: DateRangePreset[];
    defaultValue?: DateRange;
    value?: DateRange;
    onChange?: (dateRange: DateRange | undefined) => void;
} & PickerProps;

const DateRangePicker = ({ presets, ...props }: RangeDatePickerProps) => {
    if (presets) {
        validatePresets(presets, props);
    }

    return <RangeDatePicker presets={presets} {...(props as RangeProps)} />;
};

DateRangePicker.displayName = "DateRangePicker";

export {
    DatePicker,
    DateRangePicker,
    type DatePreset,
    type DateRangePreset,
    type DateRange,
};
