'use strict';

var clsx = require('clsx');
var React = require('react');
var reactIntl = require('react-intl');
require('../common/theme.js');
require('../common/direction.js');
require('../common/propsValues/control.js');
require('../common/propsValues/breakpoint.js');
var size = require('../common/propsValues/size.js');
var typography = require('../common/propsValues/typography.js');
require('../common/propsValues/width.js');
require('../common/propsValues/type.js');
var dateMode = require('../common/propsValues/dateMode.js');
var monthFormat = require('../common/propsValues/monthFormat.js');
require('../common/propsValues/position.js');
require('../common/propsValues/layouts.js');
require('../common/propsValues/status.js');
require('../common/propsValues/sentiment.js');
require('../common/propsValues/profileType.js');
require('../common/propsValues/variant.js');
require('../common/propsValues/scroll.js');
require('../common/propsValues/markdownNodeType.js');
require('../common/fileType.js');
require('@transferwise/icons');
require('../common/closeButton/CloseButton.messages.js');
var jsxRuntime = require('react/jsx-runtime');
require('@transferwise/formatting');
var getMonthNames = require('../common/dateUtils/getMonthNames/getMonthNames.js');
var isDateValid = require('../common/dateUtils/isDateValid/isDateValid.js');
var isMonthAndYearFormat = require('../common/dateUtils/isMonthAndYearFormat/isMonthAndYearFormat.js');
var getFormatForLocale = require('../common/dateUtils/getFormatForLocale/getFormatForLocale.js');
var contexts = require('../inputs/contexts.js');
var DateInput_messages = require('./DateInput.messages.js');
var convertToLocalMidnight = require('./utils/convertToLocalMidnight/convertToLocalMidnight.js');
var Body = require('../body/Body.js');
var Input = require('../inputs/Input.js');
var SelectInput = require('../inputs/SelectInput.js');

const DateInput = ({
  'aria-labelledby': ariaLabelledByProp,
  'aria-label': ariaLabel,
  disabled = false,
  size: size$1 = size.Size.MEDIUM,
  value,
  dayLabel,
  dayAutoComplete,
  monthLabel,
  yearLabel,
  yearAutoComplete,
  monthFormat: monthFormat$1 = monthFormat.MonthFormat.LONG,
  mode = dateMode.DateMode.DAY_MONTH_YEAR,
  onChange,
  onFocus,
  onBlur,
  placeholders,
  id: idProp,
  selectProps = {}
}) => {
  const inputAttributes = contexts.useInputAttributes({
    nonLabelable: true
  });
  const id = idProp ?? inputAttributes.id;
  const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes['aria-labelledby'];
  const {
    locale,
    formatMessage
  } = reactIntl.useIntl();
  const getDateObject = () => {
    if (value && isDateValid.isDateValid(value)) {
      return typeof value === 'string' ? convertToLocalMidnight.convertToLocalMidnight(value) : value;
    }
    return undefined;
  };
  const getInitialDate = unit => {
    if (value && isDateValid.isDateValid(value)) {
      const dateObject = getDateObject();
      if (typeof value === 'string' && isMonthAndYearFormat.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] = React.useState(() => getInitialDate('day'));
  const [displayDay, setDisplayDay] = React.useState(day?.toString());
  const [month, setMonth] = React.useState(() => getInitialDate('month'));
  const [year, setYear] = React.useState(() => getInitialDate('year'));
  const [displayYear, setDisplayYear] = React.useState(year?.toString());
  const [lastBroadcastedValue, setLastBroadcastedValue] = React.useState(getDateObject);
  const monthNames = getMonthNames.getMonthNames(locale, monthFormat$1);
  dayLabel ||= formatMessage(DateInput_messages.dayLabel);
  monthLabel ||= formatMessage(DateInput_messages.monthLabel);
  yearLabel ||= formatMessage(DateInput_messages.yearLabel);
  placeholders = {
    day: placeholders?.day || formatMessage(DateInput_messages.dayPlaceholder),
    month: placeholders?.month || formatMessage(DateInput_messages.monthLabel),
    year: placeholders?.year || formatMessage(DateInput_messages.yearPlaceholder)
  };
  const getDateAsString = date => {
    if (!isDateValid.isDateValid(date)) {
      return '';
    }
    switch (mode) {
      case dateMode.DateMode.MONTH_YEAR:
        return [date.getFullYear(), `0${date.getMonth() + 1}`.slice(-2)].join('-');
      case dateMode.DateMode.DAY_MONTH_YEAR:
      default:
        return [date.getFullYear(), `0${date.getMonth() + 1}`.slice(-2), `0${date.getDate()}`.slice(-2)].join('-');
    }
  };
  const getSelectElement = () => {
    return /*#__PURE__*/jsxRuntime.jsxs("label", {
      className: "d-flex flex-column",
      children: [/*#__PURE__*/jsxRuntime.jsx(Body, {
        type: typography.Typography.BODY_DEFAULT,
        children: monthLabel
      }), /*#__PURE__*/jsxRuntime.jsx(SelectInput.SelectInput, {
        id: `${id}:month`,
        name: "month",
        disabled: disabled,
        placeholder: placeholders?.month,
        items: Array.from({
          length: 12
        }, (_, index) => ({
          type: 'option',
          value: index
        })),
        size: size$1,
        value: month,
        renderValue: selectedValue => /*#__PURE__*/jsxRuntime.jsx(SelectInput.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.isDateValid(dateValue)) {
      broadcastNewValue(null);
      return;
    }
    if (mode === dateMode.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.DateMode.MONTH_YEAR;
  const monthWidth = clsx.clsx({
    'col-sm-8': monthYearOnly,
    'col-sm-5': !monthYearOnly
  });
  const getMonth = () => {
    return /*#__PURE__*/jsxRuntime.jsx("div", {
      className: monthWidth,
      children: getSelectElement()
    });
  };
  const getDay = () => {
    return /*#__PURE__*/jsxRuntime.jsx("div", {
      className: "col-sm-3",
      children: /*#__PURE__*/jsxRuntime.jsxs("label", {
        children: [/*#__PURE__*/jsxRuntime.jsx(Body, {
          type: typography.Typography.BODY_DEFAULT,
          children: dayLabel
        }), /*#__PURE__*/jsxRuntime.jsx("div", {
          className: `input-group input-group-${size$1}`,
          children: /*#__PURE__*/jsxRuntime.jsx(Input.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__*/jsxRuntime.jsx("div", {
      className: "col-sm-4",
      children: /*#__PURE__*/jsxRuntime.jsxs("label", {
        children: [/*#__PURE__*/jsxRuntime.jsx(Body, {
          type: typography.Typography.BODY_DEFAULT,
          children: yearLabel
        }), /*#__PURE__*/jsxRuntime.jsx("div", {
          className: `input-group input-group-${size$1}`,
          children: /*#__PURE__*/jsxRuntime.jsx(Input.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 = getFormatForLocale.MDY.has(locale);
  const yearFirst = getFormatForLocale.YMD.has(locale);
  return /*#__PURE__*/jsxRuntime.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__*/jsxRuntime.jsx("div", {
      className: "row",
      children: (() => {
        if (monthYearOnly) {
          return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
            children: [!yearFirst && getMonth(), getYear(), yearFirst && getMonth()]
          });
        }
        if (monthBeforeDay) {
          return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
            children: [getMonth(), getDay(), getYear()]
          });
        }
        if (yearFirst) {
          return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
            children: [getYear(), getMonth(), getDay()]
          });
        }
        return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.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;
}

module.exports = DateInput;
//# sourceMappingURL=DateInput.js.map
