import { clsx } from 'clsx';
import { useState } from 'react';
import { useIntl } from 'react-intl';
import '../common/theme.mjs';
import '../common/direction.mjs';
import '../common/propsValues/control.mjs';
import '../common/propsValues/breakpoint.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/icons';
import '../common/closeButton/CloseButton.messages.mjs';
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import '@transferwise/formatting';
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 { useInputAttributes } from '../inputs/contexts.mjs';
import messages from './DateInput.messages.mjs';
import { convertToLocalMidnight } from './utils/convertToLocalMidnight/convertToLocalMidnight.mjs';
import Body from '../body/Body.mjs';
import { Input } from '../inputs/Input.mjs';
import { SelectInput, SelectInputOptionContent } from '../inputs/SelectInput.mjs';

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 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);
  dayLabel ||= formatMessage(messages.dayLabel);
  monthLabel ||= formatMessage(messages.monthLabel);
  yearLabel ||= formatMessage(messages.yearLabel);
  placeholders = {
    day: placeholders?.day || formatMessage(messages.dayPlaceholder),
    month: placeholders?.month || formatMessage(messages.monthLabel),
    year: placeholders?.year || formatMessage(messages.yearPlaceholder)
  };
  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: monthLabel
      }), /*#__PURE__*/jsx(SelectInput, {
        id: `${id}:month`,
        name: "month",
        disabled: disabled,
        placeholder: placeholders?.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 monthYearOnly = mode === DateMode.MONTH_YEAR;
  const monthWidth = clsx({
    'col-sm-8': monthYearOnly,
    'col-sm-5': !monthYearOnly
  });
  const getMonth = () => {
    return /*#__PURE__*/jsx("div", {
      className: monthWidth,
      children: getSelectElement()
    });
  };
  const getDay = () => {
    return /*#__PURE__*/jsx("div", {
      className: "col-sm-3",
      children: /*#__PURE__*/jsxs("label", {
        children: [/*#__PURE__*/jsx(Body, {
          type: Typography.BODY_DEFAULT,
          children: dayLabel
        }), /*#__PURE__*/jsx("div", {
          className: `input-group input-group-${size}`,
          children: /*#__PURE__*/jsx(Input, {
            id: `${id}:day`,
            type: "text",
            inputMode: "numeric",
            pattern: "[0-9]*",
            name: "day",
            autoComplete: dayAutoComplete,
            value: displayDay || '',
            placeholder: placeholders?.day,
            disabled: disabled,
            min: 1,
            max: 31,
            maxLength: 2,
            onChange: event => handleDayChange(event)
          })
        })]
      })
    });
  };
  const getYear = () => {
    return /*#__PURE__*/jsx("div", {
      className: "col-sm-4",
      children: /*#__PURE__*/jsxs("label", {
        children: [/*#__PURE__*/jsx(Body, {
          type: Typography.BODY_DEFAULT,
          children: yearLabel
        }), /*#__PURE__*/jsx("div", {
          className: `input-group input-group-${size}`,
          children: /*#__PURE__*/jsx(Input, {
            id: `${id}:year`,
            type: "text",
            inputMode: "numeric",
            pattern: "[0-9]*",
            name: "year",
            autoComplete: yearAutoComplete,
            placeholder: placeholders?.year,
            value: displayYear || '',
            disabled: disabled,
            min: 0,
            max: 9999,
            maxLength: 6,
            onChange: event => handleYearChange(event)
          })
        })]
      })
    });
  };
  const monthBeforeDay = MDY.has(locale);
  const yearFirst = YMD.has(locale);
  return /*#__PURE__*/jsx("div", {
    className: "tw-date",
    ...inputAttributes,
    id: id,
    "aria-labelledby": ariaLabelledBy,
    "aria-label": ariaLabel,
    role: "group" // Add role attribute to indicate container for interactive elements
    ,
    onFocus: event => shouldPropagateOnFocus(event) ? onFocus && onFocus(event) : event.stopPropagation(),
    onBlur: event => shouldPropagateOnBlur(event) ? onBlur && 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 targetParent = target.closest('.tw-date');
  const relatedParent = relatedTarget && relatedTarget.closest('.tw-date');
  return targetParent !== relatedParent;
}
// Should only propagate if the relatedTarget or the activeElement is not part of this DateInput component.
function shouldPropagateOnBlur({
  target,
  relatedTarget
}) {
  const blurElementParent = target.closest('.tw-date');
  // Even though FocusEvent.relatedTarget is supported by IE
  // (https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/relatedTarget)
  // "IE11 sets document.activeElement to the next focused element before the blur event is called."
  // (https://stackoverflow.com/a/49325196/986241)
  // Therefore if the relatedTarget is null, we try the document.activeElement,
  // which may contain the HTML element that is gaining focus
  const focusElement = relatedTarget || (document.activeElement !== target ? document.activeElement : null);
  const focusElementParent = focusElement && focusElement.closest('.tw-date');
  return blurElementParent !== focusElementParent;
}

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