export enum UnitMs {
  Second = 1000,
  Minute = 60000,
  Hour = 60 * 60000,
  Day = 24 * 60 * 60000,
  Week = 7 * 24 * 60 * 60000,
  Year = 52 * 7 * 24 * 60 * 60000,
}

export const TIME_UNIT_BUCKETS: [
  key: Intl.RelativeTimeFormatUnit,
  unit: number,
][] = [
  ['seconds', UnitMs.Second],
  ['minutes', UnitMs.Minute],
  ['hours', UnitMs.Hour],
  ['days', UnitMs.Day],
  ['weeks', UnitMs.Week],
  ['years', UnitMs.Year],
];

export const rtfByStyle = {
  long: new Intl.RelativeTimeFormat('en', { style: 'long' }),
  narrow: new Intl.RelativeTimeFormat('en', { style: 'narrow' }),
};

export function formatRelativeTime(
  relativeTimeMilliseconds: number,
  style: keyof typeof rtfByStyle = 'long',
  justNowText?: string,
  justNowThreshold = 30000 // 30 seconds
) {
  if (justNowText && Math.abs(relativeTimeMilliseconds) < justNowThreshold) {
    return justNowText;
  }
  const rtf = rtfByStyle[style];
  return rtf.format(...getRelativeTimeMagnitude(relativeTimeMilliseconds));
}

/**
 * Converts milliseconds to the most appropriate time magnitude
 */
export function getRelativeTimeMagnitude(
  relativeTimeMilliseconds: number
): [magnitude: number, unit: Intl.RelativeTimeFormatUnit] {
  const magnitudeMs = Math.abs(relativeTimeMilliseconds);
  let timeUnitBucket = TIME_UNIT_BUCKETS[0];
  for (let i = 1; i < TIME_UNIT_BUCKETS.length; i++) {
    if (magnitudeMs <= TIME_UNIT_BUCKETS[i][1]) {
      break;
    }
    timeUnitBucket = TIME_UNIT_BUCKETS[i];
  }
  // NOTE: The rounding is NOT symmetrical for past vs. future edge cases.
  // For example, 90 seconds becomes "1 minute ago" or "in 2 minutes".
  // Although ir might make sense to normalize them, this is currently
  // following more of a loose everyday speech kind of thing: recent events
  // are treated as more immediate and urgent, whereas future events have a
  // little extra padding built in.
  return [
    Math.round(relativeTimeMilliseconds / timeUnitBucket[1]),
    timeUnitBucket[0],
  ];
}
