import { isDate } from '@astral/utils/date/isDate';
import { useEffect, useRef, useState } from 'react';
import { formatDate, isMaskedDateSyntacticallyComplete, parseDate, } from '../../../utils/date';
/**
 * Хук для управления значением для MaskField
 */
export const useMaskedValue = ({ currentValue, mask, onChangeValue, }) => {
    const [maskedValue, setMaskedValue] = useState(() => currentValue ? formatDate(currentValue, mask) : '');
    const maskedValueRef = useRef(maskedValue);
    /**
     * Ввод в маску: синхронизируем локальное значение и ref (ref нужен на blur и после выбора даты из календаря,
     * чтобы не читать устаревший state).
     * `onChangeValue` вызываем только при пустой строке (`null`) или когда маска синтаксически полная —
     * иначе partial не уходит наружу до завершения ввода или до blur (см. `handleMaskedValueBlur`).
     */
    const handleMaskedValueChange = (value) => {
        setMaskedValue(value);
        maskedValueRef.current = value;
        if (!value) {
            onChangeValue?.(null, value);
            return;
        }
        if (!isMaskedDateSyntacticallyComplete(value, mask)) {
            return;
        }
        onChangeValue?.(parseDate(value, mask), value);
    };
    /**
     * Blur поля: если осталась непустая неполная маска — один раз отдаём `Invalid Date` в `onChangeValue`,
     * чтобы формы могли показать ошибку. Пустая строка и полная маска не дублируют уже отправленный `onChange`.
     */
    const handleMaskedValueBlur = () => {
        const currentMaskedValue = maskedValueRef.current;
        if (!currentMaskedValue) {
            return;
        }
        if (isMaskedDateSyntacticallyComplete(currentMaskedValue, mask)) {
            return;
        }
        onChangeValue?.(new Date(Number.NaN), currentMaskedValue);
    };
    const handleChangeMaskedDate = (date) => {
        const formatted = formatDate(date, mask);
        setMaskedValue(formatted);
        maskedValueRef.current = formatted;
        onChangeValue?.(date, formatted);
    };
    // здесь происходит реакция на изменение value из вне (управляемый компонент)
    useEffect(() => {
        // если новое значение пустое, то сбрасываем значение MaskField
        if (!currentValue) {
            setMaskedValue('');
            maskedValueRef.current = '';
            return;
        }
        // здесь обрабатывается сценарий, когда в инпут вводится невалидная дата и при этом currentValue становится Invalid Date
        // в таком случае сравнить даты напрямую не получится
        if (!isDate(currentValue) && maskedValue) {
            return;
        }
        // сравнение только при полной маске, иначе getTime() от parseDate может быть NaN
        const isEqualValueAndMaskedDate = isMaskedDateSyntacticallyComplete(maskedValue, mask) &&
            currentValue.getTime() === parseDate(maskedValue, mask).getTime();
        // если даты не равны, то значит изменился currentValue из вне и надо синхронизировать maskedValue
        if (!isEqualValueAndMaskedDate) {
            const formatted = formatDate(currentValue, mask);
            setMaskedValue(formatted);
            maskedValueRef.current = formatted;
        }
    }, [currentValue]);
    return {
        maskedValue,
        onMaskedValueChange: handleMaskedValueChange,
        onMaskedValueBlur: handleMaskedValueBlur,
        onMaskedDateChange: handleChangeMaskedDate,
    };
};
