import { clsx } from 'clsx';
import { useRef, useState, useEffect } from 'react';
import { useIntl } from 'react-intl';
import Body from '../body/Body.mjs';
import { Input } from '../inputs/Input.mjs';
import { SelectInput } from '../inputs/SelectInput/SelectInput.mjs';
import '@transferwise/icons';
import '../dateLookup/dateTrigger/DateTrigger.messages.mjs';
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import '@headlessui/react';
import { SelectInputOptionContent } from '../inputs/SelectInput/OptionContent/SelectInputOptionContent.mjs';
import 'merge-props';
import { useInputAttributes, useFieldLabelRef } from '../inputs/contexts.mjs';
import '../header/Header.mjs';
import 'virtua';
import '../common/theme.mjs';
import '../common/direction.mjs';
import '@transferwise/neptune-tokens';
import '../common/propsValues/control.mjs';
import { Size } from '../common/propsValues/size.mjs';
import { Typography } from '../common/propsValues/typography.mjs';
import '../common/propsValues/width.mjs';
import '../common/propsValues/type.mjs';
import { DateMode } from '../common/propsValues/dateMode.mjs';
import { MonthFormat } from '../common/propsValues/monthFormat.mjs';
import '../common/propsValues/position.mjs';
import '../common/propsValues/layouts.mjs';
import '../common/propsValues/status.mjs';
import '../common/propsValues/sentiment.mjs';
import '../common/propsValues/profileType.mjs';
import '../common/propsValues/variant.mjs';
import '../common/propsValues/scroll.mjs';
import '../common/propsValues/markdownNodeType.mjs';
import '../common/fileType.mjs';
import '@transferwise/formatting';
import '../common/closeButton/CloseButton.messages.mjs';
import '../inputs/SelectInput/SelectInput.messages.mjs';
import { getMonthNames } from '../common/dateUtils/getMonthNames/getMonthNames.mjs';
import { isDateValid } from '../common/dateUtils/isDateValid/isDateValid.mjs';
import { isMonthAndYearFormat } from '../common/dateUtils/isMonthAndYearFormat/isMonthAndYearFormat.mjs';
import { MDY, YMD } from '../common/dateUtils/getFormatForLocale/getFormatForLocale.mjs';
import messages from './DateInput.messages.mjs';
import { convertToLocalMidnight } from './utils/convertToLocalMidnight/convertToLocalMidnight.mjs';

const DATE_INPUT_PARENT_ID = 'dateInput';
const DateInput = ({
  'aria-labelledby': ariaLabelledByProp,
  'aria-label': ariaLabel,
  disabled = false,
  size = Size.MEDIUM,
  value,
  dayLabel,
  dayAutoComplete,
  monthLabel,
  yearLabel,
  yearAutoComplete,
  monthFormat = MonthFormat.LONG,
  mode = DateMode.DAY_MONTH_YEAR,
  onChange,
  onFocus,
  onBlur,
  placeholders,
  id: idProp,
  selectProps = {}
}) => {
  const inputAttributes = useInputAttributes({
    nonLabelable: true
  });
  const fieldLabelRef = useFieldLabelRef();
  const dayRef = useRef(null);
  const monthRef = useRef(null);
  const yearRef = useRef(null);
  const id = idProp ?? inputAttributes.id;
  const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes['aria-labelledby'];
  const {
    locale,
    formatMessage
  } = useIntl();
  const getDateObject = () => {
    if (value && isDateValid(value)) {
      return typeof value === 'string' ? convertToLocalMidnight(value) : value;
    }
    return undefined;
  };
  const getInitialDate = unit => {
    if (value && isDateValid(value)) {
      const dateObject = getDateObject();
      if (typeof value === 'string' && isMonthAndYearFormat(value) && unit === 'day') {
        return null;
      }
      if (dateObject !== undefined) {
        switch (unit) {
          case 'year':
            return dateObject.getFullYear();
          case 'month':
            return dateObject.getMonth();
          case 'day':
            return dateObject.getDate();
          default:
            return null;
        }
      }
    }
    return null;
  };
  const [day, setDay] = useState(() => getInitialDate('day'));
  const [displayDay, setDisplayDay] = useState(day?.toString());
  const [month, setMonth] = useState(() => getInitialDate('month'));
  const [year, setYear] = useState(() => getInitialDate('year'));
  const [displayYear, setDisplayYear] = useState(year?.toString());
  const [lastBroadcastedValue, setLastBroadcastedValue] = useState(getDateObject);
  const monthNames = getMonthNames(locale, monthFormat);
  const monthYearOnly = mode === DateMode.MONTH_YEAR;
  const monthBeforeDay = MDY.has(locale);
  const yearFirst = YMD.has(locale);
  const resolvedDayLabel = dayLabel || formatMessage(messages.dayLabel);
  const resolvedMonthLabel = monthLabel || formatMessage(messages.monthLabel);
  const resolvedYearLabel = yearLabel || formatMessage(messages.yearLabel);
  const resolvedPlaceholders = {
    day: placeholders?.day || formatMessage(messages.dayPlaceholder),
    month: placeholders?.month || formatMessage(messages.monthLabel),
    year: placeholders?.year || formatMessage(messages.yearPlaceholder)
  };
  useEffect(() => {
    const labelRef = fieldLabelRef?.current;
    if (labelRef) {
      const handleLabelClick = () => {
        // Not the best way to do this, but we're forced to recreate the native Label-click behavior
        if (monthYearOnly || monthBeforeDay) {
          monthRef.current?.click();
        } else if (yearFirst) {
          yearRef.current?.focus();
        } else {
          dayRef.current?.focus();
        }
      };
      labelRef.addEventListener('click', handleLabelClick);
      return () => {
        labelRef?.removeEventListener('click', handleLabelClick);
      };
    }
  }, [fieldLabelRef, id, monthBeforeDay, monthYearOnly, yearFirst]);
  const getDateAsString = date => {
    if (!isDateValid(date)) {
      return '';
    }
    switch (mode) {
      case DateMode.MONTH_YEAR:
        return [date.getFullYear(), `0${date.getMonth() + 1}`.slice(-2)].join('-');
      case DateMode.DAY_MONTH_YEAR:
      default:
        return [date.getFullYear(), `0${date.getMonth() + 1}`.slice(-2), `0${date.getDate()}`.slice(-2)].join('-');
    }
  };
  const getSelectElement = () => {
    return /*#__PURE__*/jsxs("label", {
      className: "d-flex flex-column",
      children: [/*#__PURE__*/jsx(Body, {
        type: Typography.BODY_DEFAULT,
        children: resolvedMonthLabel
      }), /*#__PURE__*/jsx(SelectInput, {
        triggerRef: monthRef,
        id: `${id}:month`,
        parentId: DATE_INPUT_PARENT_ID,
        name: "month",
        disabled: disabled,
        placeholder: resolvedPlaceholders.month,
        items: Array.from({
          length: 12
        }, (_, index) => ({
          type: 'option',
          value: index
        })),
        size: size,
        value: month,
        renderValue: selectedValue => /*#__PURE__*/jsx(SelectInputOptionContent, {
          title: monthNames[selectedValue]
        }),
        onChange: selectedValue => handleMonthChange(selectedValue),
        ...selectProps
      })]
    });
  };
  const isDayValid = (newDay, newMonth, newYear) => {
    const maxDay = new Date(newYear, newMonth + 1, 0).getDate();
    return newDay <= maxDay;
  };
  const handleInternalValue = (newDay = day, newMonth = month, newYear = year) => {
    if (newDay == null || newDay === 0 || newMonth == null || newYear == null || newYear === 0) {
      broadcastNewValue(null);
      return;
    }
    if (!isDayValid(newDay, newMonth, newYear)) {
      broadcastNewValue(null);
      return;
    }
    const dateValue = new Date(newYear, newMonth, newDay);
    if (newYear < 100) {
      dateValue.setFullYear(newYear);
    }
    if (!isDateValid(dateValue)) {
      broadcastNewValue(null);
      return;
    }
    if (mode === DateMode.MONTH_YEAR) {
      if (newMonth !== month || newYear !== year) {
        broadcastNewValue(dateValue);
      }
    } else if (newDay !== day || newMonth !== month || newYear !== year) {
      broadcastNewValue(dateValue);
    }
  };
  const handleDayChange = event => {
    const newDayString = event.target.value.replace(/\D/g, '');
    const newDayNumber = Number.parseInt(newDayString, 10);
    setDay(newDayNumber);
    setDisplayDay(newDayString);
    handleInternalValue(newDayNumber, month, year);
  };
  const handleMonthChange = selectedMonth => {
    if (selectedMonth === null) {
      setMonth(null);
      handleInternalValue(day, null, year);
      return;
    }
    setMonth(selectedMonth);
    handleInternalValue(day, selectedMonth, year);
  };
  const handleYearChange = event => {
    const newYearString = event.target.value.replace(/\D/g, '');
    const newYearNumber = Number.parseInt(newYearString, 10);
    if (newYearString.length >= 4 && newYearString.length <= 6) {
      setYear(newYearNumber);
      setDisplayYear(newYearString);
      handleInternalValue(day, month, newYearNumber);
    } else {
      setYear(null);
      setDisplayYear(newYearString);
      handleInternalValue(day, month, null);
    }
  };
  const broadcastNewValue = newValue => {
    if (newValue !== lastBroadcastedValue) {
      setLastBroadcastedValue(newValue);
      onChange(newValue != null ? getDateAsString(newValue) : null);
    }
  };
  const monthWidth = clsx({
    'col-sm-8 tw-date--month': monthYearOnly,
    'col-sm-5 tw-date--month': !monthYearOnly
  });
  const getMonth = () => {
    return /*#__PURE__*/jsx("div", {
      className: monthWidth,
      children: getSelectElement()
    });
  };
  const getDay = () => {
    return /*#__PURE__*/jsx("div", {
      className: "col-sm-3 tw-date--day",
      children: /*#__PURE__*/jsxs("label", {
        children: [/*#__PURE__*/jsx(Body, {
          type: Typography.BODY_DEFAULT,
          children: resolvedDayLabel
        }), /*#__PURE__*/jsx("div", {
          className: `input-group input-group-${size} ${disabled ? 'disabled' : ''}`,
          children: /*#__PURE__*/jsx(Input, {
            ref: dayRef,
            id: `${id}:day`,
            type: "text",
            inputMode: "numeric",
            pattern: "[0-9]*",
            name: "day",
            autoComplete: dayAutoComplete,
            value: displayDay || '',
            placeholder: resolvedPlaceholders.day,
            disabled: disabled,
            min: 1,
            max: 31,
            maxLength: 2,
            onChange: event => handleDayChange(event)
          })
        })]
      })
    });
  };
  const getYear = () => {
    return /*#__PURE__*/jsx("div", {
      className: "col-sm-4 tw-date--year",
      children: /*#__PURE__*/jsxs("label", {
        children: [/*#__PURE__*/jsx(Body, {
          type: Typography.BODY_DEFAULT,
          children: resolvedYearLabel
        }), /*#__PURE__*/jsx("div", {
          className: `input-group input-group-${size} ${disabled ? 'disabled' : ''}`,
          children: /*#__PURE__*/jsx(Input, {
            ref: yearRef,
            id: `${id}:year`,
            type: "text",
            inputMode: "numeric",
            pattern: "[0-9]*",
            name: "year",
            autoComplete: yearAutoComplete,
            placeholder: resolvedPlaceholders.year,
            value: displayYear || '',
            disabled: disabled,
            min: 0,
            max: 9999,
            maxLength: 6,
            onChange: event => handleYearChange(event)
          })
        })]
      })
    });
  };
  return /*#__PURE__*/jsx("fieldset", {
    id: id,
    className: "tw-date",
    "aria-describedby": inputAttributes['aria-describedby'],
    "aria-invalid": inputAttributes['aria-invalid'],
    "aria-labelledby": ariaLabelledBy,
    "aria-label": ariaLabel,
    "data-wds-dateinput": "",
    onFocus: event => shouldPropagateOnFocus(event) ? onFocus?.(event) : event.stopPropagation(),
    onBlur: event => shouldPropagateOnBlur(event) ? onBlur?.(event) : event.stopPropagation(),
    children: /*#__PURE__*/jsx("div", {
      className: "row",
      children: (() => {
        if (monthYearOnly) {
          return /*#__PURE__*/jsxs(Fragment, {
            children: [!yearFirst && getMonth(), getYear(), yearFirst && getMonth()]
          });
        }
        if (monthBeforeDay) {
          return /*#__PURE__*/jsxs(Fragment, {
            children: [getMonth(), getDay(), getYear()]
          });
        }
        if (yearFirst) {
          return /*#__PURE__*/jsxs(Fragment, {
            children: [getYear(), getMonth(), getDay()]
          });
        }
        return /*#__PURE__*/jsxs(Fragment, {
          children: [getDay(), getMonth(), getYear()]
        });
      })()
    })
  });
};
// Should only propagate if the relatedTarget is not part of this DateInput component.
function shouldPropagateOnFocus({
  target,
  relatedTarget
}) {
  const blurredElementParent = target.closest('[data-wds-dateinput]');
  const focusedElementParent = relatedTarget?.closest('[data-wds-dateinput]');
  return blurredElementParent !== focusedElementParent;
}
// Should only propagate if the focus-gaining element is not part
// of this DateInput component or the (dropdown) of the month select.
function shouldPropagateOnBlur({
  target,
  relatedTarget
}) {
  const blurredElementParent = target.closest('[data-wds-dateinput]');
  const focusedElementParent = relatedTarget?.closest('[data-wds-dateinput]');
  return blurredElementParent !== focusedElementParent && !target?.closest(`[data-wds-parent="${DATE_INPUT_PARENT_ID}"]`) && !relatedTarget?.closest(`[data-wds-parent="${DATE_INPUT_PARENT_ID}"]`);
}

export { DateInput as default };
//# sourceMappingURL=DateInput.mjs.map
