import { jsxs, jsx } from "react/jsx-runtime";
import { parse } from "date-fns";
import { enGB } from "date-fns/locale";
import * as React from "react";
import ReactDatePicker from "react-datepicker";
import { FaRegCalendar, FaChevronLeft, FaChevronRight } from "react-icons/fa";
import { ImClock } from "react-icons/im";
import { useBindingState } from "../../form/hooks/useBindingState.js";
import { concat } from "../../utils/classNames.js";
import "../../utils/globals.js";
import { stripNullOrUndefined } from "../../utils/objects.js";
import { assertNever } from "../../utils/typescript.js";
import "zod";
import { useDidUpdateEffect } from "../../hooks/useDidUpdateEffect.js";
import { onBlurWorkaround } from "../../workarounds/radixDialog.js";
import { Button } from "../button/button.component.js";
import { useArmstrongConfig } from "../config/config.context.js";
import { Input } from "../input/input.component.js";
import { Label } from "../label/label.component.js";
import { Select } from "../select/select.component.js";
import { ValidationErrors } from "../validationErrors/validationErrors.component.js";
import { formatDate, getMonths, getYears } from "./dateTimeInput.utils.js";
import "react-datepicker/dist/react-datepicker.css";
import "./dateTimeInput.theme.css.js";
const defaultDateFormat = "dd/MM/yyyy";
const defaultTimeFormat = "HH:mm";
const defaultDateAndTimeFormat = `${defaultDateFormat} ${defaultTimeFormat}`;
const defaultLocale = enGB;
const DropdownHeader = ({ changeMonth, changeYear, date, min, max, locale = defaultLocale }) => {
  const monthOptions = React.useMemo(() => {
    return getMonths(date.getFullYear(), locale, min, max).map(({ index, name, disabled }) => ({
      id: index,
      content: name,
      disabled
    }));
  }, [date, locale, min, max]);
  const yearOptions = React.useMemo(() => {
    return getYears(min, max).map((y) => ({ id: y, content: y.toString() }));
  }, [min, max]);
  return jsxs("div", { className: "arm-date-time-input-header dropdown", children: [jsx(Select, { className: "arm-date-time-dropdown-select", options: monthOptions, onSelectOption: changeMonth, currentValue: date.getMonth(), clearable: false, displaySize: "small" }), jsx(Select, { className: "arm-date-time-dropdown-select", options: yearOptions, onSelectOption: changeYear, currentValue: date.getFullYear(), clearable: false, displaySize: "small" })] });
};
const LeftAlignHeader = (props) => {
  return jsxs("div", { className: "arm-date-time-input-header left-align", children: [jsx("span", { className: "arm-left-align-date", children: formatDate(props.monthDate, "MMMM yyyy") }), jsxs("div", { className: "arm-left-align-date-navigation", children: [jsx(Button, { type: "button", className: "arm-date-time-input-header-button left-align-button", displayStyle: "blank", onClick: props.decreaseMonth, disabled: props.prevMonthButtonDisabled, children: jsx(FaChevronLeft, { className: "arm-date-time-input-header-icon" }) }), jsx(Button, { type: "button", className: "arm-date-time-input-header-button left-align-button", displayStyle: "blank", onClick: props.increaseMonth, disabled: props.nextMonthButtonDisabled, children: jsx(FaChevronRight, { className: "arm-date-time-input-header-icon" }) })] })] });
};
const CenteredHeader = (props) => {
  return jsxs("div", { className: "arm-date-time-input-header centered", children: [jsx(Button, { type: "button", className: "arm-date-time-input-header-button", displayStyle: "blank", onClick: props.decreaseMonth, disabled: props.prevMonthButtonDisabled, children: jsx(FaChevronLeft, { className: "arm-date-time-input-header-icon" }) }), jsx("span", { children: formatDate(props.monthDate, "MMMM yyyy") }), jsx(Button, { type: "button", className: "arm-date-time-input-header-button", displayStyle: "blank", onClick: props.increaseMonth, disabled: props.nextMonthButtonDisabled, children: jsx(FaChevronRight, { className: "arm-date-time-input-header-icon" }) })] });
};
const SingleDateTimeInput = React.forwardRef(({ config, selectsRange, className, bind, value, onChange, validationErrorMessages, monthSelectVariant, mode, native, format, locale, statusClassName, autoValidate, showCalendarOnLeftOverlayClick, onBlur, ...inputProps }, ref) => {
  const datePickerRef = React.useRef(null);
  const [date, setDate, bindDateConfig] = useBindingState(bind, {
    validationErrorMessages,
    value,
    onChange,
    autoValidate
  });
  const globals = useArmstrongConfig({
    autoValidate: bindDateConfig.autoValidate
  });
  const renderCustomHeader = React.useCallback((customHeaderProps) => {
    return jsxs("div", { className: "customer-header-container", children: [monthSelectVariant === "dropdown" && jsx(DropdownHeader, { ...customHeaderProps, min: (config == null ? void 0 : config.minDate) ?? void 0, max: (config == null ? void 0 : config.maxDate) ?? void 0 }), monthSelectVariant === "left-align" && jsx(LeftAlignHeader, { ...customHeaderProps }), (!monthSelectVariant || monthSelectVariant === "centered") && jsx(CenteredHeader, { ...customHeaderProps })] });
  }, [monthSelectVariant, config]);
  const compiledFormat = React.useMemo(() => {
    if (format) {
      return format;
    }
    switch (mode) {
      case "date":
        return defaultDateFormat;
      case "time":
        return defaultTimeFormat;
      default:
        assertNever(mode);
        return "";
    }
  }, [mode, format]);
  const compiledConfig = React.useMemo(() => {
    return {
      // initial two props can be overridden with config
      monthsShown: 1,
      dateFormat: compiledFormat,
      ...config,
      renderCustomHeader,
      renderDayContents: (day) => jsx("div", { className: "arm-date-time-input-day-contents", children: day }),
      showTimeSelect: mode === "time",
      showTimeSelectOnly: mode === "time"
    };
  }, [mode, config, renderCustomHeader, compiledFormat]);
  const dateVal = React.useMemo(() => date ? parse(date, compiledFormat, /* @__PURE__ */ new Date(), { locale }) : void 0, [date, compiledFormat, locale]);
  useDidUpdateEffect(() => {
    if (globals.autoValidate) {
      bindDateConfig.validate();
    }
    bindDateConfig.setTouched(true);
  }, [dateVal]);
  const leftOverlay = React.useMemo(() => {
    if (inputProps.leftOverlay === false)
      return void 0;
    if (inputProps.leftOverlay)
      return inputProps.leftOverlay;
    if (mode === "time")
      return jsx(ImClock, {});
    return jsx(FaRegCalendar, {});
  }, [inputProps.leftOverlay, mode]);
  const onBlurEvent = React.useCallback((event) => {
    onBlurWorkaround(event);
    return onBlur == null ? void 0 : onBlur(event);
  }, [onBlur]);
  return jsx(ReactDatePicker, { ...stripNullOrUndefined(compiledConfig), ref: datePickerRef, className, locale, dateFormat: compiledFormat, disabled: inputProps.disabled, required: inputProps.required, onBlur: onBlurEvent, customInput: jsx(Input, { ref, ...inputProps, leftOverlay: showCalendarOnLeftOverlayClick && leftOverlay ? jsx("button", { type: "button", className: "arm-date-time-overlay-button", disabled: inputProps.disabled, onClick: () => {
    var _a;
    return (_a = datePickerRef.current) == null ? void 0 : _a.setOpen(true);
  }, children: leftOverlay }) : leftOverlay, className: concat(inputProps.inputClassName, "arm-date-time-input"), validationErrorMessages: bindDateConfig.validationErrorMessages }), selectsRange: false, selected: dateVal, onChange: (newValue) => setDate == null ? void 0 : setDate(formatDate(newValue, compiledFormat)) });
});
SingleDateTimeInput.displayName = "SingleDateTimeInput";
SingleDateTimeInput.defaultProps = {
  locale: defaultLocale,
  showCalendarOnLeftOverlayClick: true
};
const RangeDateTimeInput = React.forwardRef(({ config, selectsRange, startBind, endBind, startValue, endValue, className, onChange, validationErrorMessages, native, format, locale, autoValidate, showCalendarOnLeftOverlayClick, ...inputProps }, ref) => {
  const datePickerRef = React.useRef(null);
  const [startDate, setStartDate, bindStartDateConfig] = useBindingState(startBind, {
    validationErrorMessages,
    value: startValue,
    autoValidate
  });
  const [endDate, setEndDate, bindEndDateConfig] = useBindingState(endBind, {
    // only pass in validationErrorMessages once for date range as errors will be combined!
    validationErrorMessages: [],
    value: endValue,
    autoValidate
  });
  const globals = useArmstrongConfig({
    autoValidate: bindEndDateConfig.autoValidate ?? bindStartDateConfig.autoValidate
  });
  const compiledConfig = React.useMemo(() => {
    return {
      // initial values can be overridden with config
      monthsShown: 2,
      ...config,
      renderDayContents: (day) => jsx("div", { className: "arm-date-time-input-day-contents", children: day })
    };
  }, [config]);
  const startDateVal = startDate ? parse(startDate, format, /* @__PURE__ */ new Date(), { locale }) : void 0;
  const endDateVal = endDate ? parse(endDate, format, /* @__PURE__ */ new Date(), { locale }) : void 0;
  useDidUpdateEffect(() => {
    if (globals.autoValidate) {
      bindEndDateConfig.validate();
      bindStartDateConfig.validate();
    }
    bindStartDateConfig.setTouched(true);
    bindEndDateConfig.setTouched(true);
  }, [endDate]);
  useDidUpdateEffect(() => {
    if (globals.autoValidate && bindStartDateConfig.isTouched && bindEndDateConfig.isTouched) {
      bindEndDateConfig.validate();
      bindStartDateConfig.validate();
    }
  }, [startDate]);
  return jsx(ReactDatePicker, { ...stripNullOrUndefined(compiledConfig), ref: datePickerRef, locale, className: concat("arm-date-time-input", className), dateFormat: format, disabled: inputProps.disabled, customInput: jsx(Input, { type: "text", ref, ...inputProps, leftOverlay: showCalendarOnLeftOverlayClick && inputProps.leftOverlay ? jsx("button", { type: "button", className: "arm-date-time-overlay-button", disabled: inputProps.disabled, onClick: () => {
    var _a;
    return (_a = datePickerRef.current) == null ? void 0 : _a.setOpen(true);
  }, children: inputProps.leftOverlay }) : inputProps.leftOverlay, validationErrorMessages: [
    ...bindStartDateConfig.validationErrorMessages,
    ...bindEndDateConfig.validationErrorMessages
  ] }), selectsRange: true, startDate: startDateVal, endDate: endDateVal, onChange: (newValue) => {
    let hasChanged = false;
    if (newValue == null ? void 0 : newValue[0]) {
      setStartDate == null ? void 0 : setStartDate(formatDate(newValue == null ? void 0 : newValue[0], format));
      hasChanged = true;
    }
    if (newValue == null ? void 0 : newValue[1]) {
      setEndDate == null ? void 0 : setEndDate(formatDate(newValue == null ? void 0 : newValue[1], format));
      hasChanged = true;
    }
    if (hasChanged) {
      onChange == null ? void 0 : onChange(newValue == null ? void 0 : newValue.map((nv) => formatDate(nv, format)));
    }
  } });
});
RangeDateTimeInput.displayName = "RangeDateTimeInput";
RangeDateTimeInput.defaultProps = {
  leftOverlay: jsx(FaRegCalendar, {}),
  format: defaultDateFormat,
  locale: defaultLocale,
  showCalendarOnLeftOverlayClick: true
};
const NativeDateTimeInput = React.forwardRef(({ mode, selectsRange, native, ...props }, ref) => {
  return jsx(Input, { ref, type: mode === "date-time" ? "datetime-local" : mode, ...props });
});
NativeDateTimeInput.displayName = "NativeDateTimeInput";
const SingleDateAndTimeInput = React.forwardRef(({ className, bind, mode, validationErrorMessages, disableOnPending, hideIconOnStatus, displaySize, statusPosition, requiredIndicator, scrollValidationErrorsIntoView, validationMode, errorIcon, validationErrorsClassName, value, onChange, dateInputConfig, timeInputConfig, format, locale, disabled, required, dateInputProps = {}, timeInputProps = {}, timeInputDisplayFormat, dateInputDisplayFormat, timeInputRef, selectsRange, native, monthSelectVariant, error, label, labelId, labelClassName, autoValidate, ...nativeProps }, ref) => {
  const [dateTime, setDateTime, bindConfig] = useBindingState(bind, {
    validationErrorMessages,
    value,
    onChange,
    validationMode,
    autoValidate
  });
  const globals = useArmstrongConfig({
    validationMode: bindConfig.validationMode,
    disableControlOnPending: disableOnPending,
    hideInputErrorIconOnStatus: hideIconOnStatus,
    inputDisplaySize: displaySize,
    inputStatusPosition: statusPosition,
    requiredIndicator,
    validationErrorIcon: bindConfig.validationErrorIcon,
    scrollValidationErrorsIntoView,
    autoValidate: bindConfig.autoValidate
  });
  const incomingDateValue = React.useMemo(() => {
    if (!dateTime)
      return void 0;
    const asDate = parse(dateTime, format, /* @__PURE__ */ new Date(), { locale });
    return formatDate(asDate, dateInputDisplayFormat);
  }, [dateTime, format, locale, dateInputDisplayFormat]);
  const incomingTimeValue = React.useMemo(() => {
    if (!dateTime)
      return void 0;
    const asDate = parse(dateTime, format, /* @__PURE__ */ new Date(), { locale });
    return formatDate(asDate, timeInputDisplayFormat);
  }, [dateTime, format, locale, timeInputDisplayFormat]);
  const [dateValue, setDateValue] = React.useState(incomingDateValue);
  const [timeValue, setTimeValue] = React.useState(incomingTimeValue);
  React.useEffect(() => setDateValue(incomingDateValue), [incomingDateValue]);
  React.useEffect(() => setTimeValue(incomingTimeValue), [incomingTimeValue]);
  React.useEffect(() => {
    if (dateValue && timeValue) {
      const dateAsDate = parse(dateValue, dateInputDisplayFormat, /* @__PURE__ */ new Date(), { locale });
      const timeAsDate = parse(timeValue, timeInputDisplayFormat, /* @__PURE__ */ new Date(), { locale });
      const combinedDate = new Date(dateAsDate.getFullYear(), dateAsDate.getMonth(), dateAsDate.getDate(), timeAsDate.getHours(), timeAsDate.getMinutes(), timeAsDate.getSeconds(), timeAsDate.getMilliseconds());
      setDateTime == null ? void 0 : setDateTime(formatDate(combinedDate, format));
    }
  }, [dateInputDisplayFormat, dateValue, format, locale, timeInputDisplayFormat, timeValue]);
  useDidUpdateEffect(() => {
    if (globals.autoValidate) {
      bindConfig.validate();
    }
    bindConfig.setTouched(true);
  }, [dateTime]);
  return jsxs("div", { className: concat("arm-date-and-time-input-container", className), ...nativeProps, children: [label && jsx(Label, { className: concat("arm-input-base-label arm-date-and-time-input-label", labelClassName), required, requiredIndicator: globals.requiredIndicator, htmlFor: labelId, displaySize: globals.inputDisplaySize, children: label }), jsxs("div", { className: "arm-date-and-time-inputs", children: [jsx("div", { className: "arm-date-and-time-input arm-date-input", children: jsx(SingleDateTimeInput, { mode: "date", ref, locale, format: dateInputDisplayFormat, config: dateInputConfig, value: dateValue, onChange: setDateValue, displaySize: globals.inputDisplaySize, validationMode: bindConfig.validationMode, disabled, statusPosition: globals.inputStatusPosition, disableOnPending: globals.disableControlOnPending, hideIconOnStatus: globals.hideInputErrorIconOnStatus, required, requiredIndicator: globals.requiredIndicator, monthSelectVariant, error: error || !!(validationErrorMessages == null ? void 0 : validationErrorMessages.length), ...dateInputProps }) }), jsx("div", { className: "arm-date-and-time-input arm-time-input", children: jsx(SingleDateTimeInput, { mode: "time", locale, format: timeInputDisplayFormat, config: timeInputConfig, ref: timeInputRef, value: timeValue, onChange: setTimeValue, displaySize: globals.inputDisplaySize, validationMode: bindConfig.validationMode, disabled, statusPosition: globals.inputStatusPosition, disableOnPending: globals.disableControlOnPending, hideIconOnStatus: globals.hideInputErrorIconOnStatus, required, requiredIndicator: globals.requiredIndicator, error: error || !!(validationErrorMessages == null ? void 0 : validationErrorMessages.length), ...timeInputProps }) })] }), !!(validationErrorMessages == null ? void 0 : validationErrorMessages.length) && bindConfig.shouldShowValidationErrorMessage && jsx(ValidationErrors, { className: validationErrorsClassName, validationMode: globals.validationMode, validationErrors: validationErrorMessages, scrollIntoView: globals.scrollValidationErrorsIntoView })] });
});
SingleDateAndTimeInput.displayName = "SingleDateAndTimeInput";
SingleDateAndTimeInput.defaultProps = {
  format: defaultDateAndTimeFormat,
  locale: defaultLocale,
  timeInputDisplayFormat: defaultTimeFormat,
  dateInputDisplayFormat: defaultDateFormat
};
const DateTimeInput = React.forwardRef(
  (props, ref) => {
    if (props.selectsRange) {
      return jsx(RangeDateTimeInput, { ref, ...props });
    }
    if (props.native) {
      return jsx(NativeDateTimeInput, { ref, ...props });
    }
    if (props.mode === "date-time") {
      return jsx(SingleDateAndTimeInput, { ref, ...props });
    }
    return jsx(SingleDateTimeInput, { ref, ...props });
  }
  // type assertion to ensure generic works with RefForwarded component
  // DO NOT CHANGE TYPE WITHOUT CHANGING THIS, FIND TYPE BY INSPECTING React.forwardRef
);
DateTimeInput.displayName = "DateTimeInput";
DateTimeInput.defaultProps = {
  selectsRange: false,
  mode: "date",
  native: false
};
export {
  DateTimeInput,
  RangeDateTimeInput,
  SingleDateAndTimeInput,
  SingleDateTimeInput
};
//# sourceMappingURL=dateTimeInput.component.js.map
