import { format, parse, parseISO } from 'date-fns';

import { useAuth } from 'src/contexts/JWTContext';
import { getCurrentLocale } from 'src/utils/locale';

export type FormatDateOptions = {
  locale?: Locale;
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
  firstWeekContainsDate?: number;
  useAdditionalWeekYearTokens?: boolean;
  useAdditionalDayOfYearTokens?: boolean;
};

export type FormatDateProps = {
  date: Date | string;
  pattern?: string;
  options?: FormatDateOptions;
};

// ISO 8601: date-only strings (YYYY-MM-DD) are treated as UTC by both
// `new Date()` and `parseISO`, causing a -1 day offset in negative UTC
// timezones (e.g. UTC-3). Appending T00:00:00 forces local-time interpretation.
const parseDateString = (date: Date | string) => {
  if (typeof date !== 'string') return date;
  if (/^\d{4}-\d{2}-\d{2}$/.test(date))
    return parse(date, 'yyyy-MM-dd', new Date());
  return parseISO(date);
};

export default function useFormatDate() {
  const { user } = useAuth();
  const locale = getCurrentLocale(user);

  const formatDayWithoutYear = (date: Date | string) => {
    const dateToFormat = parseDateString(date);
    // Intl.DateTimeFormat is used instead of date-fns format() because it respects the locale's
    // native day/month ordering (e.g. "6 de noviembre" vs "November 6"), which would require
    // hardcoding a pattern in date-fns and break for non-European locales.
    const formatter = new Intl.DateTimeFormat(locale.code, {
      day: 'numeric',
      month: 'long',
    });
    return formatter.format(dateToFormat);
  };

  const formatDate = (
    date: Date | string,
    pattern: string = 'P',
    options?: FormatDateOptions,
  ) => {
    // Patterns: https://date-fns.org/v4.1.0/docs/format
    // Default pattern: P (04/29/2024)

    const parsedDate = parseDateString(date);

    return format(parsedDate, pattern, {
      locale,
      ...options,
    });
  };

  return { formatDate, formatDayWithoutYear };
}
