import { add, format, isValid, parse } from 'date-fns';
import { useMemo } from 'react';
import { joinClassNames } from '../../util/joinClassNames';
import { ComboBox } from './ComboBox/ComboBox';
import { ComboBoxOption } from './ComboBox/ComboBoxOption';
import { TextInput } from './TextInput';

/**
 * @param {object} props
 * @param {boolean} [props.allowCustomEntry] can the user type in their own time that is not in the popup combobox list
 * @param {string} [props.className]
 * @param {string} [props.defaultValue]
 * @param {string} [props.errorMessage]
 * @param {boolean} [props.hasTimePopup] is there a popup from which the user can select the time?
 * @param {string} props.id
 * @param {import('react').Ref<HTMLDivElement>} [props.innerRef]
 * @param {boolean} [props.isClearable] should the clearable "X" icon be shown; is auto set to true if onClear is passed in
 * @param {boolean} [props.isDisabled]
 * @param {boolean} [props.isRequired]
 * @param {string} props.label
 * @param {string} [props.labelClassName]
 * @param {string} [props.name]
 * @param {(newValue: string) => void} [props.onChange] can be omitted to be uncontrolled
 * @param {() => void} [props.onClear]
 * @param {string} [props.placeholder]
 * @param {string} [props.timeFormat] use `date-fns` modifiers for formatting the time options
 * @param {number} [props.timeRangeIncrement] for popup, what increment (in minutes) for the options given to the user
 * @param {string} [props.timeRangeBegin] options in popup can start (inclusive) at a given time; format per `props.timeFormat`
 * @param {string} [props.timeRangeEnd] options in popup can end at the given time (inclusive); format per `props.timeFormat`
 * @param {string} [props.value]
 * @param {string} [props.wrapperClassName]
 * @returns {import('react').JSX.Element}
 */
export function TimeInput({
  allowCustomEntry,
  className,
  defaultValue,
  errorMessage,
  hasTimePopup = true,
  id,
  innerRef,
  isClearable,
  isDisabled,
  isRequired,
  label,
  labelClassName,
  name,
  onChange,
  onClear,
  placeholder,
  timeFormat = 'h:mm aaa',
  timeRangeBegin,
  timeRangeEnd,
  timeRangeIncrement = 15,
  value,
  wrapperClassName,
  ...rest
}) {
  const timeOptions = useMemo(
    () => {
      const defaultStartDate = new Date(new Date().setHours(0, 0, 0, 0));
      const defaultEndDate = new Date(new Date().setHours(23, 59, 0, 0));

      let optionsBeginDate = (timeRangeBegin && parse(timeRangeBegin, timeFormat, new Date())) || null;
      optionsBeginDate = (optionsBeginDate && isValid(optionsBeginDate)) ? optionsBeginDate : defaultStartDate;

      let optionsEndDate = (timeRangeEnd && parse(timeRangeEnd, timeFormat, new Date())) || null;
      optionsEndDate = (optionsEndDate && isValid(optionsEndDate)) ? optionsEndDate : defaultEndDate;

      const timeOptionsRet = [];
      for (
        let loopDate = optionsBeginDate;
        loopDate.getTime() <= optionsEndDate.getTime();
        loopDate = add(loopDate, { minutes: timeRangeIncrement })
      ) {
        timeOptionsRet.push(format(loopDate, timeFormat));
      }

      return timeOptionsRet;
    },
    [timeRangeBegin, timeRangeEnd, timeRangeIncrement, timeFormat]
  );

  const clockIcon = useMemo(
    () => (
      <span className={joinClassNames('utds-icon-before-clock', 'time-input__clock-icon', isDisabled && 'time-input__clock-icon--is-disabled', !hasTimePopup && 'time-input__clock-icon--static')} aria-hidden="true" />
    ),
    [isDisabled, hasTimePopup]
  );

  return (
    <div className={joinClassNames('time-input__wrapper', wrapperClassName)} ref={innerRef}>
      {
        hasTimePopup
          ? (
            <ComboBox
              // COMMON PROPS: make sure these match with TextInput
              className={className}
              defaultValue={defaultValue}
              errorMessage={errorMessage}
              id={id}
              isClearable={isClearable}
              isDisabled={isDisabled}
              isRequired={isRequired}
              label={label}
              labelClassName={labelClassName}
              name={name || id}
              onClear={isClearable ? onClear : undefined}
              placeholder={placeholder}
              value={value}
              // END COMMON PROPS
              allowCustomEntry={allowCustomEntry}
              iconCallback={() => clockIcon}
              onChange={onChange}
              // eslint-disable-next-line react/jsx-props-no-spreading
              {...rest}
            >
              {
                timeOptions.map((timeOption) => (
                  <ComboBoxOption
                    key={`time-input__${id}__${timeOption}`}
                    label={timeOption}
                    value={timeOption}
                  />
                ))
              }
            </ComboBox>
          )
          : (
            <TextInput
              // COMMON PROPS: make sure these match with ComboBox
              className={className}
              defaultValue={defaultValue}
              errorMessage={errorMessage}
              id={id}
              isClearable={isClearable}
              isDisabled={isDisabled}
              isRequired={isRequired}
              label={label}
              labelClassName={labelClassName}
              name={name || id}
              onClear={isClearable ? onClear : undefined}
              placeholder={placeholder}
              value={value}
              // END COMMON PROPS
              onChange={(e) => onChange?.(e.target.value)}
              rightContent={clockIcon}
              // eslint-disable-next-line react/jsx-props-no-spreading
              {...rest}
            />
          )
      }
    </div>
  );
}
