import { isAppLocale, localeHtmlLang } from '@/i18n/routing';
import { getLocalPersianParts } from '@/lib/i18n/persianCalendar';

export const FORMAT_EMPTY = '—';

/** BCP 47 tag for Intl APIs (`fa` → `fa-IR`, etc.). */
export function intlLocale(locale: string): string {
  return isAppLocale(locale) ? localeHtmlLang(locale) : locale;
}

export function usesPersianCalendar(locale: string): boolean {
  return locale === 'fa';
}

function withPersianCalendar(
  locale: string,
  options: Intl.DateTimeFormatOptions,
): Intl.DateTimeFormatOptions {
  if (!usesPersianCalendar(locale)) {
    return options;
  }
  return { calendar: 'persian', numberingSystem: 'arabext', ...options };
}

export function toValidDate(value: Date | string | number | null | undefined): Date | null {
  if (value == null) return null;
  const date = value instanceof Date ? value : new Date(value);
  return Number.isNaN(date.getTime()) ? null : date;
}

export function createAppDateFormatter(
  locale: string,
  options: Intl.DateTimeFormatOptions = {},
): Intl.DateTimeFormat {
  return new Intl.DateTimeFormat(intlLocale(locale), withPersianCalendar(locale, options));
}

export const APP_DATE = {
  short: { year: 'numeric', month: 'short', day: 'numeric' } satisfies Intl.DateTimeFormatOptions,
  withWeekday: {
    weekday: 'short',
    year: 'numeric',
    month: 'short',
    day: 'numeric',
  } satisfies Intl.DateTimeFormatOptions,
  dayPicker: {
    weekday: 'short',
    month: 'short',
    day: 'numeric',
    year: 'numeric',
  } satisfies Intl.DateTimeFormatOptions,
  chartDay: { weekday: 'short', month: 'short', day: 'numeric' } satisfies Intl.DateTimeFormatOptions,
  history: {
    weekday: 'short',
    month: 'short',
    day: 'numeric',
    year: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
  } satisfies Intl.DateTimeFormatOptions,
  activity: {
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  } satisfies Intl.DateTimeFormatOptions,
} as const;

export function formatAppDate(
  value: Date | string | number | null | undefined,
  locale: string,
  options: Intl.DateTimeFormatOptions = APP_DATE.short,
): string {
  const date = toValidDate(value);
  if (!date) return FORMAT_EMPTY;
  return createAppDateFormatter(locale, options).format(date);
}

export function formatAppTime(
  value: Date | string | number | null | undefined,
  locale: string,
  options: Intl.DateTimeFormatOptions = { hour: 'numeric', minute: '2-digit' },
): string {
  const date = toValidDate(value);
  if (!date) return FORMAT_EMPTY;
  const timeOptions: Intl.DateTimeFormatOptions = {
    ...options,
    ...(usesPersianCalendar(locale) ? { numberingSystem: 'arabext' } : {}),
  };
  return new Intl.DateTimeFormat(intlLocale(locale), timeOptions).format(date);
}

export function formatAppDateTime(
  value: Date | string | number | null | undefined,
  locale: string,
  options: Intl.DateTimeFormatOptions = { dateStyle: 'medium', timeStyle: 'short' },
): string {
  const date = toValidDate(value);
  if (!date) return FORMAT_EMPTY;
  return new Intl.DateTimeFormat(intlLocale(locale), withPersianCalendar(locale, options)).format(date);
}

export function formatAppTimeRange(
  start: Date | string | number,
  end: Date | string | number,
  locale: string,
  options: Intl.DateTimeFormatOptions = { hour: 'numeric', minute: '2-digit' },
): string {
  return `${formatAppTime(start, locale, options)} – ${formatAppTime(end, locale, options)}`;
}

/** Schedule axis labels (hour/minute from midnight). */
export function formatAppMinuteOfDay(minute: number, locale: string): string {
  const hours = Math.floor(minute / 60);
  const minutes = minute % 60;
  const date = new Date(2000, 0, 1, hours, minutes, 0, 0);
  return formatAppTime(date, locale, {
    hour: 'numeric',
    minute: '2-digit',
    hour12: !usesPersianCalendar(locale),
  });
}

export function formatAppTableDate(
  value: Date | string | number | null | undefined,
  locale: string,
): string {
  return formatAppDate(value, locale, APP_DATE.short);
}

export function formatAppNumber(
  value: number,
  locale: string,
  options?: Intl.NumberFormatOptions,
): string {
  return new Intl.NumberFormat(intlLocale(locale), options).format(value);
}

/** Calendar parts (year/day) — no thousands separators. */
export function formatAppInteger(value: number, locale: string): string {
  return new Intl.NumberFormat(intlLocale(locale), {
    useGrouping: false,
    ...(usesPersianCalendar(locale) ? { numberingSystem: 'arabext' } : {}),
  }).format(value);
}

/** ScheduleDayPicker / calendar field trigger label — year without grouping. */
export function formatAppPickerDateLabel(date: Date, locale: string): string {
  const formatter = createAppDateFormatter(locale, APP_DATE.dayPicker);
  const yearNum = usesPersianCalendar(locale)
    ? getLocalPersianParts(date).year
    : date.getFullYear();
  return formatter
    .formatToParts(date)
    .map((part) => (part.type === 'year' ? formatAppInteger(yearNum, locale) : part.value))
    .join('');
}
