/**
 * Calendar helpers for chat timestamps.
 *
 * `ChatMessage.createdAt` is an epoch-millisecond value, so it represents an
 * absolute UTC instant. Calendar grouping is deliberately performed in the
 * viewer's display timezone: the same instant may belong to Monday in UTC and
 * Tuesday in Asia/Makassar.
 */

export interface CalendarDateParts {
  year: number;
  month: number;
  day: number;
}

export function getCalendarDateParts(timestamp: number, timeZone: string): CalendarDateParts {
  const parts = new Intl.DateTimeFormat('en-US', {
    timeZone,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).formatToParts(new Date(timestamp));

  const values = Object.fromEntries(
    parts
      .filter((part) => part.type === 'year' || part.type === 'month' || part.type === 'day')
      .map((part) => [part.type, Number(part.value)]),
  );

  return {
    year: values.year,
    month: values.month,
    day: values.day,
  };
}

export function getCalendarDayKey(timestamp: number, timeZone: string): string {
  const { year, month, day } = getCalendarDateParts(timestamp, timeZone);
  return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
}

function calendarDayNumber(timestamp: number, timeZone: string): number {
  const { year, month, day } = getCalendarDateParts(timestamp, timeZone);
  return Math.floor(Date.UTC(year, month - 1, day) / 86_400_000);
}

function capitalizeLabel(label: string, locale?: string): string {
  if (!label) return label;
  return label[0].toLocaleUpperCase(locale) + label.slice(1);
}

export function formatMessageDateLabel(
  timestamp: number,
  options: {
    locale?: string;
    timeZone: string;
    now?: number;
  },
): string {
  const { locale, timeZone, now = Date.now() } = options;
  const dayDelta = calendarDayNumber(timestamp, timeZone) - calendarDayNumber(now, timeZone);

  if (dayDelta === 0 || dayDelta === -1) {
    return capitalizeLabel(
      new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(dayDelta, 'day'),
      locale,
    );
  }

  const messageYear = getCalendarDateParts(timestamp, timeZone).year;
  const currentYear = getCalendarDateParts(now, timeZone).year;
  return new Intl.DateTimeFormat(locale, {
    timeZone,
    weekday: 'long',
    month: 'long',
    day: 'numeric',
    ...(messageYear === currentYear ? {} : { year: 'numeric' as const }),
  }).format(new Date(timestamp));
}
