import { useMemo } from 'react';

import { useLocale } from '../useLocale';
import { useTimeZone } from '../useTimeZone';

import {
  DateStyleFormat,
  DayFormat,
  HourFormat,
  MinuteFormat,
  MonthFormat,
  SecondFormat,
  TimeStyleFormat,
  WeekdayFormat,
  YearFormat,
} from './constants';

/**
 * Options for {@link useFormattedDateTime} hook
 */
export interface UseFormattedDateTimeOptions {
  /**
   * The date formatting style preset.
   *
   * dateStyle can be used with timeStyle, but not with other options (e.g. weekday, hour, month, etc.).
   */
  dateStyle?: DateStyleFormat;
  /**
   * The time formatting style
   *
   * timeStyle can be used with dateStyle, but not with other options (e.g. weekday, hour, month, etc.).
   */
  timeStyle?: TimeStyleFormat;
  /**
   * The representation of the weekday.
   */
  weekday?: WeekdayFormat;
  /**
   * The representation of the year.
   */
  year?: YearFormat;
  /**
   * The representation of the month.
   */
  month?: MonthFormat;
  /**
   * The representation of the day.
   */
  day?: DayFormat;
  /**
   * The representation of the hour.
   */
  hour?: HourFormat;
  /**
   * The representation of the minute.
   */
  minute?: MinuteFormat;
  /**
   * The representation of the second.
   */
  second?: SecondFormat;
}

/**
 * Function for date formatting
 *
 * @param date Date in ISO format YYYY-MM-DDTHH:mm:ss.sssZ
 * @see useFormattedDateTime
 */
type FormattedDateTime = (isoDate: string) => string;

/**
 * Returns the function for date formatting
 *
 * @example
 * const formatDate = useFormattedDateTime({ dateStyle: DateStyleFormat.Medium });
 * formatDate('2010-01-01'); // Jan 1, 2010
 * @example
 * const formatDate = useFormattedDateTime({
 *   day: DayFormat.TwoDigit,
 *   month: MonthFormat.TwoDigit,
 *   year: YearFormat.Numeric
 * });
 * formatDate('2020-12-31'); // 31.12.2020
 */
export function useFormattedDateTime({
  timeStyle,
  dateStyle,
  weekday,
  year,
  month,
  day,
  hour,
  minute,
  second,
}: UseFormattedDateTimeOptions): FormattedDateTime {
  const locale = useLocale();
  const timeZone = useTimeZone();

  return useMemo<FormattedDateTime>(() => {
    const formatter = new Intl.DateTimeFormat(locale, {
      timeZone,
      timeStyle,
      dateStyle,
      weekday,
      year,
      month,
      day,
      hour,
      minute,
      second,
    });

    return (isoDate) => {
      return formatter.format(Date.parse(isoDate));
    };
  }, [locale, timeZone, timeStyle, dateStyle, weekday, year, month, day, hour, minute, second]);
}
