import React from 'react';
import moment from 'moment';
import isEmpty from 'lodash-es/isEmpty';
import omit from 'lodash-es/omit';
import { MESSAGE_DISPLAY_LOCATION } from '../form-field';
import { MESSAGE_TYPES } from '../message';
import { ACCENT_TYPES, Button } from '../button';
import { INITIAL_DIRECTION } from './datetime-range-picker';
import { useTranslation } from '../hooks/use-translation';
import { DATE_RANGE_ERROR_TYPES } from './datetime-range-picker-panel';
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
const DEFAULT_DATETIME_FORMAT = 'YYYY-MM-DDTHH:mm:ss.SSSSSSZ';
const VALIDATION_ENTITY = {
  days: {
    start: 'Start Date',
    end: 'End Date'
  },
  months: {
    start: 'Start Month',
    end: 'End Month'
  }
};
export function useValidateOnClick() {
  const {
    t
  } = useTranslation();
  return function validateOnClick({
    start,
    end,
    minStart,
    maxEnd,
    viewMode,
    dateTimeFormat,
    sameDateError
  }) {
    const [minStartTrimmed, maxEndTrimmed] = [minStart, maxEnd].map(datetime => datetime ? truncateDateTimeToFormat(datetime, dateTimeFormat) : null);
    const startErrors = {};
    let endErrors = {};
    if (minStartTrimmed && start?.isBefore(minStartTrimmed)) {
      startErrors[DATE_RANGE_ERROR_TYPES.START_BEFORE_MIN] = t('{{fieldName}} cannot be before {{date}}.', {
        fieldName: VALIDATION_ENTITY[viewMode].start,
        date: minStartTrimmed.format(dateTimeFormat)
      });
    }
    if (maxEndTrimmed && start?.isAfter(maxEndTrimmed)) {
      startErrors[DATE_RANGE_ERROR_TYPES.START_AFTER_MAX] = t('{{fieldName}} cannot be after {{date}}.', {
        fieldName: VALIDATION_ENTITY[viewMode].start,
        date: maxEndTrimmed.format(dateTimeFormat)
      });
    }
    if (maxEndTrimmed && end?.isAfter(maxEndTrimmed)) {
      endErrors[DATE_RANGE_ERROR_TYPES.END_AFTER_MAX] = t('{{fieldName}} cannot be after {{date}}.', {
        fieldName: VALIDATION_ENTITY[viewMode].end,
        date: maxEndTrimmed.format(dateTimeFormat)
      });
    }
    if (minStartTrimmed && end?.isBefore(minStartTrimmed)) {
      endErrors[DATE_RANGE_ERROR_TYPES.END_AFTER_MIN] = t('{{fieldName}} cannot be before {{date}}.', {
        fieldName: VALIDATION_ENTITY[viewMode].end,
        date: minStartTrimmed.format(dateTimeFormat)
      });
    }
    if (!start?.isValid()) {
      startErrors[DATE_RANGE_ERROR_TYPES.INVALID_START_DATE] = t('You need to set {{fieldName}}', {
        fieldName: VALIDATION_ENTITY[viewMode].start
      });
    }
    if (!end?.isValid()) {
      endErrors[DATE_RANGE_ERROR_TYPES.INVALID_END_DATE] = t('You need to set {{fieldName}}', {
        fieldName: VALIDATION_ENTITY[viewMode].end
      });
    }
    if (start && !end?.isValid()) {
      endErrors[DATE_RANGE_ERROR_TYPES.INVALID_END_DATE] = t('You need to set {{fieldName}}', {
        fieldName: VALIDATION_ENTITY[viewMode].end
      });
    }
    if (start && end && end.isValid()) {
      endErrors = omit(endErrors, [DATE_RANGE_ERROR_TYPES.INVALID_END_DATE]);
    }
    if (sameDateError && start?.isSame(end)) {
      startErrors[DATE_RANGE_ERROR_TYPES.START_END_SAME] = t('{{startField}} and {{endField}} cannot be the same', {
        startField: VALIDATION_ENTITY[viewMode].start,
        endField: VALIDATION_ENTITY[viewMode].end
      });
    }
    return {
      startErrors,
      endErrors
    };
  };
}

/** Checks whether a string can be strictly parsed as a moment object following a provided datetime format
 *
 * @param {string} proposedDateTime
 * @param {string} dateTimeFormat
 * @returns {boolean}
 */
export function isValidDateTime(proposedDateTime, dateTimeFormat) {
  try {
    convertStringToMoment(proposedDateTime, {
      dateTimeFormat
    })?.isValid();
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
  } catch (err) {
    return false;
  }
  return true;
}
export function useGetDateTimeValidityError() {
  const {
    t
  } = useTranslation();
  return function getDateTimeValidityError(dateTime, dateTimeFormat) {
    if (moment.isMoment(dateTime)) {
      return;
    }
    if (typeof dateTime === 'string') {
      if (isValidDateTime(dateTime, dateTimeFormat)) {
        return;
      }
      return t('Must follow {{dateTimeFormat}} format', {
        dateTimeFormat
      });
    }
    return t('Expected a datetime');
  };
}
export function getValidityFromErrors(errorMapping) {
  let validityValues;
  if (isEmpty(errorMapping)) {
    validityValues = '';
  } else {
    validityValues = Object.values(errorMapping);
  }
  return {
    type: MESSAGE_TYPES.ERROR,
    value: validityValues,
    displayLocation: MESSAGE_DISPLAY_LOCATION.SUMMARY
  };
}
export function customizeCalendarView(selectedDate, start, end, className, viewMode) {
  let classes = selectedDate.isBetween(start, end, viewMode) ? `${className} in-selecting-range` : className;
  classes = selectedDate.isSame(start, viewMode) || selectedDate.isSame(end, viewMode) ? `${classes} rdtActive` : classes.replace('rdtActive', '');
  return classes;
}
export function customizeRenderCalendarView(mode, pickerRef, value, dateTimeFormat, timeFormat, renderDefault) {
  if (mode === 'time') {
    const setDayView = () => pickerRef.current?.setState({
      // We are hacking the Datetime pickers setState function here
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      currentView: 'days'
    });
    return /*#__PURE__*/_jsxs(_Fragment, {
      children: [/*#__PURE__*/_jsx(Button, {
        testId: "apply-button-time-view",
        className: "apply-button",
        accentType: ACCENT_TYPES.SECONDARY,
        onClick: setDayView,
        children: moment(value).format(dateTimeFormat)
      }), renderDefault()]
    });
  }
  if (mode === 'days') {
    const setTimeView = () => pickerRef.current?.setState({
      // We are hacking the Datetime pickers setState function here
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      currentView: 'time'
    });
    return /*#__PURE__*/_jsxs(_Fragment, {
      children: [renderDefault(), timeFormat && /*#__PURE__*/_jsx(Button, {
        testId: "apply-button-month-view",
        className: "apply-button",
        accentType: ACCENT_TYPES.SECONDARY,
        onClick: setTimeView,
        children: moment(value).format(timeFormat)
      })]
    });
  }
  return renderDefault();
}
export function isNavigationAvailableForMonthsView(currentView, leftPickerRef, rightPickerRef, quantity) {
  const leftPickerViewDate = leftPickerRef?.current?.state?.viewDate;
  const rightPickerViewDate = rightPickerRef?.current?.state?.viewDate;
  const minLeftMonth = moment(leftPickerViewDate).add(quantity, 'month');
  return currentView === 'months' && minLeftMonth.month() === rightPickerViewDate?.month() && minLeftMonth.year() === rightPickerViewDate?.year();
}
export function isNavigationAvailableForYearsView(currentView, leftPickerRef, rightPickerRef, quantity) {
  const leftPickerViewDate = leftPickerRef?.current?.state?.viewDate;
  const rightPickerViewDate = rightPickerRef?.current?.state?.viewDate;
  const minLeftYear = moment(leftPickerViewDate).add(quantity, 'year');
  return currentView === 'years' && minLeftYear.year() === rightPickerViewDate?.year();
}
export function isMonthRelatedToTimePicker(pickerRef, selectedValue) {
  return pickerRef?.current?.state?.currentView === 'time' && pickerRef?.current?.state?.viewDate.isSame(selectedValue, 'month');
}
export function getLeftCalendarInitialView(initialDirection, start, end, viewMode) {
  if (start?.isSame(end, viewMode)) {
    return initialDirection === INITIAL_DIRECTION.PAST ? moment(start).subtract(1, viewMode) : moment(start);
  }
  return moment(start);
}
export function getRightCalendarInitialView(initialDirection, start, end, viewMode) {
  if (start?.isSame(end, viewMode)) {
    return initialDirection === INITIAL_DIRECTION.PAST ? moment(start) : moment(start).add(1, viewMode);
  }
  return moment(start).add(1, viewMode);
}

/** Strictly parses a string using a provided datetime format and returns a moment object
 *
 * @param {string|null} datetimeString - A string-representation of a datetime
 * @param {string} [dateTimeFormat=DEFAULT_DATETIME_FORMAT] - The datetime format used to parse the datetime string
 * @param {boolean} [strictParse=true] - If true and the string does not conform to the provided dateFormat,
 *    then an error will be thrown
 * @param {boolean} [allowNil=false] - If false and the string is actually null or undefined, then an error is thrown
 * @returns {moment.Moment|null} - Will return a moment object if the datetime string was successfully parsed as a valid
 *    datetime. May return null if a null datetime-string was passed in and allowNil ===  true.
 */

export function convertStringToMoment(datetimeString, {
  dateTimeFormat = DEFAULT_DATETIME_FORMAT,
  strictParse = true,
  allowNil = false
} = {}) {
  if (datetimeString == null) {
    if (allowNil) {
      return null;
    }
    throw Error(`datetime string cannot be null`);
  }
  const dateTime = moment.utc(datetimeString, dateTimeFormat, strictParse);
  if (!dateTime.isValid()) {
    throw Error(`Could not create a valid moment object from ${datetimeString}`);
  }
  return dateTime;
}

/** Takes a moment object and returns a copy, but following the provided datetime format
 *
 * @param {moment.Moment} dateTime
 * @param {string} dateTimeFormat
 * @returns {moment.Moment}
 */
export function truncateDateTimeToFormat(dateTime, dateTimeFormat) {
  return convertStringToMoment(dateTime.format(dateTimeFormat), {
    dateTimeFormat
  });
}

/** Takes a date format and a time format (both strings) and returns their concatenation with a space in-between
 *
 * @param {string} dateFormat
 * @param {string} timeFormat
 * @returns {string}
 */
export function getDateTimeFormat(dateFormat, timeFormat) {
  if (!timeFormat) {
    return dateFormat;
  }
  if (!dateFormat) {
    return timeFormat;
  }
  return `${dateFormat} ${timeFormat}`;
}