import React, { forwardRef, useRef, useState, useEffect } from "react";
import cls from "classnames";
import { useForkRef, useOutsideClick } from "../../hooks";
import { getSizeValueFromProp } from "../../utils";
import { processTimeInput, delimiter } from "./utils";
import { base, LeftHelper, StyledInput, StyledTimePickerGrid } from "./TimePicker.styles";
import { classes } from "./TimePicker.tokens";
import { FloatingPopover } from "./FloatingPopover";
import { base as sizeCSS } from "./variations/_size/base";
import { base as viewCSS } from "./variations/_view/base";
import { base as hintViewCSS } from "./variations/_hint-view/base";
import { base as hintSizeCSS } from "./variations/_hint-size/base";
import { base as disabledCSS } from "./variations/_disabled/base";
import { base as readonlyCSS } from "./variations/_readonly/base";
import { useKeyNavigation } from "./hooks/useKeyboardNavigation";
export const timePickerRoot = (Root)=>/*#__PURE__*/ forwardRef(({ className, // controlled
    value: outerValue, opened = false, // variations
    view, size, disabled = false, readonly = false, stretched, appearance, hasClearDivider, valueError, valueSuccess, valueEdited, // layout
    label, labelPlacement = 'outer', keepPlaceholder, required = false, requiredPlacement = 'right', hasRequiredIndicator = false, placeholder, leftHelper, contentLeft, contentRight, textBefore, textAfter, autoComplete, // hint
    hintTrigger = 'hover', hintText, hintView = 'default', hintSize = 'm', hintTargetIcon, hintTargetPlacement = 'outer', hintPlacement = 'auto', hintHasArrow, hintOffset = [
        0,
        0
    ], hintWidth, hintContentLeft, // popover-container
    frame = 'document', usePortal = false, placement = 'bottom-start', closeOnOverlayClick = true, closeOnEsc = true, disableFlip, offset, zIndex = 1000, // dropdown
    dropdownAlign = 'left', dropdownWidth, dropdownHeight, columnsQuantity = 2, min, max, multiplicityMinutes, multiplicitySeconds, onToggle, onFocus, onChange, ...rest }, ref)=>{
        const inputRef = useRef(null);
        const timeGridRootRef = useRef(null);
        const floatingPopoverRef = useRef(null);
        const rootRef = useRef(null);
        const rootForkRef = useForkRef(rootRef, ref);
        const hoursHideTimeoutRef = useRef(null);
        const minutesHideTimeoutRef = useRef(null);
        const secondsHideTimeoutRef = useRef(null);
        const [isInnerOpen, setIsInnerOpen] = useState(opened);
        const [innerTime, setInnerTime] = useState(outerValue || '');
        const [rootWidth, setRootWidth] = useState(null);
        const [, setActiveTime] = useState({
            hours: null,
            minutes: null,
            seconds: null,
            currentColumn: null
        });
        const viewValue = outerValue ?? innerTime;
        const format = columnsQuantity === 3 ? 'HH:mm:ss' : 'HH:mm';
        const dropdownWidthValue = dropdownWidth ? getSizeValueFromProp(dropdownWidth, 'rem') : undefined;
        const dropdownHeightValue = dropdownHeight ? getSizeValueFromProp(dropdownHeight, 'rem') : undefined;
        useEffect(()=>{
            return ()=>{
                [
                    hoursHideTimeoutRef,
                    minutesHideTimeoutRef,
                    secondsHideTimeoutRef
                ].forEach((timeoutRef)=>{
                    if (timeoutRef.current) {
                        clearTimeout(timeoutRef.current);
                    }
                });
            };
        }, []);
        useEffect(()=>{
            if (!viewValue) {
                return;
            }
            let timeString = viewValue;
            if (format === 'HH:mm' && viewValue.length > 5) {
                timeString = viewValue.substring(0, 5);
            }
            setInnerTime(viewValue);
            const [hh, mm, ss] = timeString.split(delimiter).map(Number);
            setActiveTime({
                hours: !Number.isNaN(hh) ? hh : null,
                minutes: !Number.isNaN(mm) ? mm : null,
                seconds: format === 'HH:mm:ss' && !Number.isNaN(ss) ? ss : null,
                currentColumn: null
            });
        }, [
            outerValue,
            format
        ]);
        useEffect(()=>{
            if (isInnerOpen && (disabled || readonly)) {
                setIsInnerOpen(false);
            }
        }, [
            disabled,
            readonly
        ]);
        useEffect(()=>{
            if (rootRef.current) {
                const width = rootRef.current.offsetWidth;
                setRootWidth(width);
            }
        }, [
            dropdownWidth,
            isInnerOpen
        ]);
        const handleToggle = ()=>{
            if (disabled || readonly) return;
            const newState = !isInnerOpen;
            setIsInnerOpen(newState);
            if (newState) {
                setActiveTime((prev)=>({
                        ...prev,
                        currentColumn: 'hours'
                    }));
            }
            onToggle?.(newState);
        };
        useOutsideClick(()=>{
            if (!isInnerOpen || !closeOnOverlayClick) {
                return;
            }
            setIsInnerOpen(false);
            onToggle?.(false);
        }, [
            floatingPopoverRef,
            timeGridRootRef
        ]);
        const handleOnChange = (formattedValues)=>{
            if (!formattedValues) {
                return;
            }
            let timeString = formattedValues.value;
            if (format === 'HH:mm' && viewValue.length > 5) {
                timeString = viewValue.substring(0, 5);
            }
            setInnerTime(timeString ?? '');
            setActiveTime({
                hours: !Number.isNaN(formattedValues.timeValues.hour) ? formattedValues.timeValues.hour : null,
                minutes: !Number.isNaN(formattedValues.timeValues.minute) ? formattedValues.timeValues.minute : null,
                seconds: format === 'HH:mm:ss' && !Number.isNaN(formattedValues.timeValues.second) ? formattedValues.timeValues.second : null,
                currentColumn: null
            });
            if (onChange) {
                onChange(formattedValues, formattedValues);
            }
        };
        const handleInputChange = (event)=>{
            const input = event.target.value;
            const cursorPos = event.target.selectionStart;
            const { innerString, values, newCursorPosition } = processTimeInput(input, format, cursorPos);
            const { hh: hours, mm: minutes, ss: seconds } = values;
            setInnerTime(innerString);
            setActiveTime((prev)=>({
                    ...prev,
                    hours,
                    minutes,
                    seconds
                }));
            const formattedValues = {
                value: innerString,
                timeValues: {
                    hour: hours,
                    minute: minutes,
                    second: seconds
                }
            };
            if (onChange) {
                onChange({
                    ...event,
                    target: {
                        ...event.target,
                        ...formattedValues
                    }
                }, formattedValues);
            }
            requestAnimationFrame(()=>{
                if (inputRef.current) {
                    inputRef.current.setSelectionRange(newCursorPosition, newCursorPosition);
                }
            });
        };
        const handleKeyDown = (event)=>{
            if (event.key === 'Enter' && !isInnerOpen) {
                event.preventDefault();
                setIsInnerOpen(true);
                setActiveTime((prev)=>({
                        ...prev,
                        currentColumn: 'hours'
                    }));
                onToggle?.(true);
            }
        };
        const handleOnKeyDown = (e)=>{
            onKeyDownNavigation(e);
            handleKeyDown(e);
        };
        const handleTimeGridRootClick = (event)=>{
            if (disabled || readonly) {
                return;
            }
            if (isInnerOpen && event.target === timeGridRootRef?.current) {
                setIsInnerOpen(false);
                if (onToggle) {
                    onToggle(false, event);
                }
            }
        };
        const { onKeyDown: onKeyDownNavigation } = useKeyNavigation({
            isCalendarOpen: isInnerOpen,
            format,
            maskWithFormat: true,
            delimiter,
            closeOnEsc,
            onToggle: handleToggle
        });
        const getActualWidth = ()=>{
            if (!rootWidth) {
                return 'fit-content';
            }
            if (dropdownWidthValue === 'fixed' || dropdownWidthValue === undefined) {
                return undefined;
            }
            if (dropdownWidth === 'fullWidth') {
                return `${rootWidth}px`;
            }
            if (String(dropdownWidth)?.includes('%') && typeof dropdownWidth === 'string') {
                const widthValue = rootWidth / 100 * parseFloat(dropdownWidth.replace('%', ''));
                return `${widthValue}px`;
            }
            return String(dropdownWidth || 'fit-content');
        };
        return /*#__PURE__*/ React.createElement(Root, {
            stretched: stretched,
            view: view,
            size: size,
            className: cls(classes.timePickerRoot, className, {
                [classes.timePickerstretched]: stretched
            }),
            disabled: disabled,
            readonly: readonly,
            ref: rootForkRef,
            ...hintText && {
                hintView,
                hintSize
            },
            ...rest
        }, /*#__PURE__*/ React.createElement(FloatingPopover, {
            ref: floatingPopoverRef,
            opened: isInnerOpen,
            onToggle: handleToggle,
            offset: offset,
            placement: placement,
            disableFlip: disableFlip,
            portal: usePortal ? frame : undefined,
            zIndex: zIndex,
            target: (referenceRef)=>/*#__PURE__*/ React.createElement(StyledInput, {
                    ref: inputRef,
                    inputWrapperRef: referenceRef,
                    className: cls({
                        [classes.timePickerError]: valueError,
                        [classes.timePickerSuccess]: valueSuccess,
                        [classes.timePickerEdited]: valueEdited
                    }),
                    value: viewValue,
                    size: size,
                    disabled: disabled,
                    readOnly: readonly,
                    appearance: appearance,
                    hasDivider: appearance === 'clear' && hasClearDivider,
                    placeholder: placeholder,
                    contentLeft: contentLeft,
                    contentRight: contentRight,
                    textBefore: textBefore,
                    textAfter: textAfter,
                    autoComplete: autoComplete,
                    onChange: handleInputChange,
                    onFocus: onFocus,
                    onKeyDown: handleOnKeyDown,
                    required: required,
                    requiredPlacement: requiredPlacement,
                    hasRequiredIndicator: hasRequiredIndicator,
                    label: label,
                    labelPlacement: labelPlacement,
                    keepPlaceholder: keepPlaceholder,
                    ...hintText ? {
                        hintText,
                        hintView,
                        hintSize,
                        hintTrigger,
                        hintTargetIcon,
                        hintPlacement,
                        hintHasArrow,
                        hintOffset,
                        hintWidth,
                        hintContentLeft,
                        hintTargetPlacement
                    } : {
                        hintText: undefined
                    }
                })
        }, /*#__PURE__*/ React.createElement(Root, {
            ref: timeGridRootRef,
            stretched: stretched,
            view: view,
            size: size,
            className: cls(classes.timePickerGridRoot, className, {
                [classes.timePickerPlacementRight]: dropdownAlign === 'right',
                [classes.timePickerFullWidth]: dropdownWidth === 'fullWidth',
                [classes.timePickerFixed]: dropdownWidth !== 'fullWidth'
            }),
            disabled: disabled,
            readonly: readonly,
            onClick: handleTimeGridRootClick
        }, /*#__PURE__*/ React.createElement(StyledTimePickerGrid, {
            view: view,
            size: size,
            format: format,
            columns: columnsQuantity,
            innerWidth: getActualWidth(),
            innerHeight: dropdownHeightValue,
            dropdownHeight: "100%",
            dropdownWidth: "fullWidth",
            value: viewValue,
            onChange: handleOnChange,
            disabled: disabled,
            min: min,
            max: max,
            multiplicityMinutes: multiplicityMinutes,
            multiplicitySeconds: multiplicitySeconds
        }))), leftHelper && /*#__PURE__*/ React.createElement(LeftHelper, {
            className: cls({
                [classes.timePickerError]: valueError,
                [classes.timePickerSuccess]: valueSuccess,
                [classes.timePickerEdited]: valueEdited
            })
        }, leftHelper));
    });
export const timePickerConfig = {
    name: 'TimePicker',
    tag: 'div',
    layout: timePickerRoot,
    base,
    variations: {
        view: {
            css: viewCSS
        },
        size: {
            css: sizeCSS
        },
        hintView: {
            css: hintViewCSS
        },
        hintSize: {
            css: hintSizeCSS
        },
        disabled: {
            css: disabledCSS,
            attrs: true
        },
        readonly: {
            css: readonlyCSS,
            attrs: true
        }
    },
    defaults: {
        size: 'm',
        view: 'default'
    }
};
