import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { forwardRef, useState, useRef, useEffect, useMemo, useImperativeHandle, useCallback } from 'react';
import { m as maskitoDateOptionsGenerator, a as maskitoWithPlaceholder, u as useMaskito, b as maskitoParseDate } from './index.esm-C2ZhC_8d.js';
import { T as TextField } from './TextField-CUVsDfWo.js';
import { u as useMergeRefs, P as Popover } from './AiMark-voHPSerQ.js';
import { D as DateTime } from './luxon-wpz4A-OQ.js';
import { m as makeZeroShortcutPreprocessor } from './makeZeroShortcutPreprocessor-CxsiGTRW.js';
import { I as Icon } from './Icon-B4uCvMU9.js';
import { D as DateModeToPlaceholderMap, a as DateModeToFormatMap, S as SvgEvent, j as jsDateToUtcDateTime, c as convertStringToDate, T as TimezoneMessage, i as isoToUtcDate, v as validateDate } from './TimezoneMessage-BrKB_psP.js';
import { u as usePrevious } from './usePrevious-Bvq-5auG.js';
import { u as useOptionallyControlledState } from './useOptionallyControlledState-DbDuos5L.js';
import { a as Calendar } from './Calendar-CekTYzdT.js';
import { m as mergeRefs } from './useMergeRefs-Dfmtq9cI.js';
import { u as useFocusWithin } from './useFocusWithin-hi77jsrB.js';
import { c as childrenToString } from './childrenToString-Bz9MqbHb.js';
import { useTrackingId } from './useTrackingId.js';

const datePlaceholderMask = ({
  mode,
  separator = "/",
  placeholder
}) => {
  const dateOptions = maskitoDateOptionsGenerator({
    mode,
    separator
  });
  const { plugins, removePlaceholder, ...placeholderOptions } = maskitoWithPlaceholder(placeholder);
  const datePlaceholderMask2 = {
    ...dateOptions,
    plugins: plugins.concat(dateOptions.plugins || []),
    preprocessors: [
      ...placeholderOptions.preprocessors,
      ...dateOptions.preprocessors,
      makeZeroShortcutPreprocessor(mode, separator)
    ],
    postprocessors: [
      ...dateOptions.postprocessors,
      ...placeholderOptions.postprocessors
    ]
  };
  return { options: datePlaceholderMask2, removePlaceholder };
};

const MaskedDateInput = forwardRef(
  ({
    onChange,
    mode = "mm/dd/yyyy",
    lastValidDate,
    disableHint = false,
    ...props
  }, ref) => {
    const placeholder = DateModeToPlaceholderMap[mode];
    const [inputValue, setInputValue] = useState(placeholder);
    const { options, removePlaceholder } = datePlaceholderMask({
      mode,
      placeholder
    });
    const maskedInputRef = useMaskito({ options });
    const inputRef = useRef(null);
    const combinedRef = useMergeRefs([maskedInputRef, inputRef, ref]);
    const previousDateRef = useRef(null);
    const previousMode = usePrevious(mode);
    useEffect(() => {
      if (mode !== previousMode) {
        setInputValue(
          (oldInputValue) => swapMode(oldInputValue, previousMode ?? mode, mode)
        );
      }
    }, [mode, previousMode]);
    useEffect(() => {
      if (lastValidDate === void 0) return;
      if (lastValidDate === previousDateRef.current) return;
      if (!lastValidDate?.equals(previousDateRef.current ?? DateTime.now())) {
        setInputValue(
          lastValidDate?.toFormat(DateModeToFormatMap[mode]) ?? placeholder
        );
        previousDateRef.current = lastValidDate;
      }
    }, [lastValidDate, mode, placeholder]);
    const currentParsedData = useMemo(() => {
      return parseInputValue(inputValue, mode, removePlaceholder);
    }, [inputValue, mode, removePlaceholder]);
    const handleChange = (event) => {
      setInputValue(event.target.value);
      const { date, isInputValid, isInputEmpty } = parseInputValue(
        event.target.value,
        mode,
        removePlaceholder
      );
      const isValueDifferent = isInputValid !== currentParsedData.isInputValid || // The input has changed validity
      isInputEmpty !== currentParsedData.isInputEmpty || // The input has changed emptiness
      date === null !== (currentParsedData.date === null) || // The input has changed from empty to non-empty or vice versa
      date !== null && lastValidDate !== null && !date.equals(lastValidDate);
      if (!isValueDifferent) return;
      onChange?.({
        date: date ?? lastValidDate ?? null,
        isInputValid,
        isInputEmpty
      });
    };
    useImperativeHandle(ref, () => {
      const input = inputRef.current;
      if (!input) return null;
      return Object.assign(input, {
        setDate: (date) => {
          setInputValue(
            date?.toFormat(DateModeToFormatMap[mode]) ?? placeholder
          );
        }
      });
    }, [mode, placeholder]);
    return /* @__PURE__ */ jsx(
      TextField,
      {
        ref: combinedRef,
        "data-date": lastValidDate?.toISODate() ?? "",
        "data-input-valid": currentParsedData.isInputValid,
        "data-input-empty": currentParsedData.isInputEmpty,
        ...props,
        showCounter: false,
        value: inputValue,
        onChange: handleChange,
        prefix: /* @__PURE__ */ jsx(Icon, { svg: SvgEvent }),
        hint: disableHint ? void 0 : `Format: ${mode}`
      }
    );
  }
);
MaskedDateInput.displayName = "MaskedDateInput";
function parseInputValue(value, mode, removePlaceholder) {
  const valueMinusPlaceholder = removePlaceholder(value);
  const jsDate = maskitoParseDate(valueMinusPlaceholder, { mode });
  const luxonDate = jsDate ? jsDateToUtcDateTime(jsDate) : null;
  return {
    date: luxonDate,
    isInputValid: !!luxonDate,
    isInputEmpty: valueMinusPlaceholder === ""
  };
}
function swapMode(inputString, previousMode, mode) {
  const { day, month, year } = divideSegments(inputString, previousMode);
  return orderSegmentsByMode(day, month, year, mode);
}
function divideSegments(value, mode) {
  const [segment1, segment2, segment3] = value.split("/");
  if (mode === "dd/mm/yyyy") {
    return { day: segment1, month: segment2, year: segment3 };
  } else if (mode === "mm/dd/yyyy") {
    return { day: segment2, month: segment1, year: segment3 };
  } else if (mode === "yyyy/mm/dd") {
    return { day: segment3, month: segment2, year: segment1 };
  }
  return { day: "__", month: "__", year: "____" };
}
function orderSegmentsByMode(day, month, year, mode) {
  if (mode === "dd/mm/yyyy") {
    return `${day}/${month}/${year}`;
  } else if (mode === "mm/dd/yyyy") {
    return `${month}/${day}/${year}`;
  } else if (mode === "yyyy/mm/dd") {
    return `${year}/${month}/${day}`;
  } else {
    return "";
  }
}

function useDateFieldSingleConversion({
  value,
  defaultValue,
  minDate,
  maxDate,
  unavailable,
  onChange
}) {
  const normalizedValue = useMemo(() => convertStringToDate(value), [value]);
  const normalizedDefaultValue = useMemo(
    () => convertStringToDate(defaultValue),
    [defaultValue]
  );
  const normalizedMinDate = useMemo(
    () => convertStringToDate(minDate),
    [minDate]
  );
  const normalizedMaxDate = useMemo(
    () => convertStringToDate(maxDate),
    [maxDate]
  );
  const normalizedUnavailableDates = useMemo(
    () => unavailable?.dates?.map((d) => convertStringToDate(d)).filter((d) => d !== null && d !== void 0),
    [unavailable?.dates]
  );
  const handleChange = useCallback(
    (change) => {
      onChange?.({
        ...change,
        date: change.date?.toISODate() ?? null
      });
    },
    [onChange]
  );
  return {
    value: normalizedValue,
    defaultValue: normalizedDefaultValue,
    minDate: normalizedMinDate,
    maxDate: normalizedMaxDate,
    unavailable: {
      dates: normalizedUnavailableDates,
      daysOfWeek: unavailable?.daysOfWeek
    },
    onChange: handleChange
  };
}

function useDateFieldSingleState({
  valueProp,
  defaultValueProp,
  onChange
}) {
  const [value, setValue] = useOptionallyControlledState({
    controlledValue: valueProp,
    defaultValue: defaultValueProp
  });
  const handleInputChange = (change) => {
    const date = change.isInputEmpty ? null : change.date?.startOf("day") ?? null;
    onChange?.({
      date,
      isInputValid: change.isInputValid,
      isInputEmpty: change.isInputEmpty
    });
    if (change.isInputValid) {
      setValue(change.isInputEmpty ? null : change.date);
    }
    if (change.isInputEmpty) {
      setValue(null);
      return;
    }
    if (change.date) {
      setValue(change.date);
    }
  };
  const handleCalendarSelection = (date) => {
    setValue(date);
    onChange?.({
      date,
      isInputValid: true,
      isInputEmpty: false
    });
  };
  return {
    value,
    setValue,
    handleInputChange,
    handleCalendarSelection
  };
}

function DateFieldSingleCalendar({
  onKeyDown,
  value,
  onSelection,
  minDate,
  maxDate,
  unavailable,
  timezone: timezoneProp,
  ...rest
}) {
  const timezone = useMemo(() => {
    return timezoneProp ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
  }, [timezoneProp]);
  const handleCalendarSelection = (data) => {
    if (data.value) {
      const date = isoToUtcDate(data.value);
      onSelection(date);
    }
  };
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsx(
      Calendar,
      {
        ...rest,
        range: false,
        onKeyDown,
        defaultFocusedDate: value?.toISODate() || DateTime.now().setZone(timezone).toISODate(),
        value: value?.toISODate() || void 0,
        onSelection: handleCalendarSelection,
        defaultTimeZone: timezone,
        minDate: minDate?.toISODate() ?? void 0,
        maxDate: maxDate?.toISODate() ?? void 0,
        unavailable: unavailable ? {
          dates: unavailable.dates?.map((d) => d.toISODate() ?? ""),
          daysOfWeek: unavailable.daysOfWeek
        } : void 0,
        _disableAutofocus: true,
        _disableFocus: true
      }
    ),
    /* @__PURE__ */ jsx(TimezoneMessage, { timezone })
  ] });
}

const DateFieldSingle = (props) => {
  const { aiMark, ...labelPropsWithoutAiMark } = props.labelProps || {};
  const data = {
    label: childrenToString(props.label),
    labelProps: labelPropsWithoutAiMark,
    description: childrenToString(props.description)
  };
  const trackingId = useTrackingId({
    name: "DateFieldSingle",
    data,
    hasOverride: !!props["data-tracking-id"]
  });
  const {
    onFocus,
    onBlur,
    disableCalendar,
    required,
    mode,
    value: valueProp,
    defaultValue: defaultValueProp,
    minDate: minDateProp,
    maxDate: maxDateProp,
    unavailable: unavailableProp,
    onChange: onChangeProp,
    label,
    timezone,
    ...rest
  } = props;
  const popoverRef = useRef(null);
  const inputRef = useRef(null);
  const {
    value: normalizedValue,
    defaultValue: normalizedDefaultValue,
    minDate,
    maxDate,
    unavailable,
    onChange
  } = useDateFieldSingleConversion({
    value: valueProp,
    defaultValue: defaultValueProp,
    onChange: onChangeProp,
    minDate: minDateProp,
    maxDate: maxDateProp,
    unavailable: unavailableProp
  });
  const handleChange = (change) => {
    onChange?.({
      ...change,
      isDateValid: validateDate({
        date: change.date,
        constraints: {
          required,
          unavailable,
          minDate: minDate ?? void 0,
          maxDate: maxDate ?? void 0
        }
      })
    });
  };
  const { value, handleInputChange, handleCalendarSelection } = useDateFieldSingleState({
    valueProp: normalizedValue,
    defaultValueProp: normalizedDefaultValue,
    onChange: handleChange
  });
  const { props: wrapperProps } = useFocusWithin({
    onBlur: (e) => {
      onBlur?.(e);
      popoverRef.current?.closePopover();
    },
    onFocus
  });
  const popoverContentRef = useRef(null);
  const currentValidity = useMemo(
    () => validateDate({
      date: value,
      constraints: {
        required,
        unavailable,
        minDate: minDate ?? void 0,
        maxDate: maxDate ?? void 0
      }
    }),
    [value, required, unavailable, minDate, maxDate]
  );
  const handleInputKeyDown = (ev) => {
    if (ev.key === "ArrowDown") {
      popoverRef.current?.openPopover();
      requestAnimationFrame(() => {
        popoverContentRef.current?.querySelector("button")?.focus();
      });
    }
  };
  const commonFieldProps = {
    ...rest,
    label,
    mode,
    onChange: handleInputChange,
    lastValidDate: value,
    required,
    autoComplete: "off",
    "data-date-valid": currentValidity,
    "data-tracking-id": trackingId,
    "aria-label": label ? void 0 : "Select a Date"
  };
  if (disableCalendar) {
    return /* @__PURE__ */ jsx(MaskedDateInput, { ref: inputRef, ...commonFieldProps });
  }
  return /* @__PURE__ */ jsx("div", { ...wrapperProps, children: /* @__PURE__ */ jsxs(Popover, { ref: popoverRef, placement: "bottom-start", role: "grid", children: [
    /* @__PURE__ */ jsx(Popover.Trigger, { children: ({ ref: iRef, onKeyDown }) => {
      const mergedRef = mergeRefs([
        iRef,
        inputRef
      ]);
      return /* @__PURE__ */ jsx(
        MaskedDateInput,
        {
          ...commonFieldProps,
          ref: mergedRef,
          onKeyDown: (ev) => {
            onKeyDown?.(ev);
            handleInputKeyDown(ev);
          },
          onClick: () => popoverRef.current?.openPopover(),
          onFocus,
          onBlur
        }
      );
    } }),
    /* @__PURE__ */ jsx(Popover.Content, { ref: popoverContentRef, "data-testid": "calendar-popover", children: /* @__PURE__ */ jsx(
      DateFieldSingleCalendar,
      {
        value,
        onSelection: (v) => {
          inputRef.current?.focus();
          handleCalendarSelection(v);
          popoverRef.current?.closePopover();
        },
        minDate,
        maxDate,
        unavailable,
        timezone
      }
    ) })
  ] }) });
};
DateFieldSingle.displayName = "DateFieldSingle";

export { DateFieldSingle as D, MaskedDateInput as M, useDateFieldSingleState as a, DateFieldSingleCalendar as b, useDateFieldSingleConversion as u };
//# sourceMappingURL=DateFieldSingle-CgMPTi1v.js.map
