/**
 * Human phrasing of device timestamps (ticket #77, lot F2).
 *
 * The list answers "is this thing still being used?", not "when exactly?", so
 * recent activity degrades from a phrase to a time to a date as it ages. Pure
 * and `now`-injectable so the boundaries are testable without faking the clock.
 *
 * Instants are **epoch milliseconds** (`*AtMs`, `number`) — the codebase-wide
 * convention, aligned with the backend store. The format is unambiguous, so
 * these functions parse nothing and tolerate no alternative encoding.
 */

/** Below this, activity reads as "now" rather than a timestamp. */
const JUST_NOW_MS = 2 * 60 * 1000;

function startOfDay(d: Date): number {
  return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
}

/** `14:32` in 24-hour form. */
function timeOfDay(d: Date): string {
  return d.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" });
}

/** `12 juil.`, with the year appended once it is no longer the current one. */
export function shortDate(ms: number, now: Date = new Date()): string {
  const d = new Date(ms);
  const sameYear = d.getFullYear() === now.getFullYear();
  return d.toLocaleDateString("fr-FR", {
    day: "numeric",
    month: "short",
    ...(sameYear ? {} : { year: "numeric" }),
  });
}

/**
 * Last-activity label: `Actif à l'instant`, `Aujourd'hui à 14:32`, `Hier`, then
 * a short date. Days are compared as calendar days, not 24-hour spans — 23:59
 * yesterday reads "Hier", not "Aujourd'hui".
 */
export function formatLastSeen(ms: number, now: Date = new Date()): string {
  const delta = now.getTime() - ms;
  // A clock skew that puts the server slightly ahead reads as "now", not as a
  // date in the future.
  if (delta < JUST_NOW_MS) return "Actif à l'instant";

  const today = startOfDay(now);
  const day = startOfDay(new Date(ms));
  if (day === today) return `Aujourd'hui à ${timeOfDay(new Date(ms))}`;
  if (day === today - 86_400_000) return "Hier";
  return shortDate(ms, now);
}

/** Secondary line: `Appairé le 12 juil.` */
export function formatPairedAt(ms: number, now: Date = new Date()): string {
  return `Appairé le ${shortDate(ms, now)}`;
}

/**
 * Remaining lifetime of a pairing code: `Expire dans 10 min`, then seconds in
 * the last minute so the panel stays honest as it runs out. `null` once expired
 * — the caller shows the expiry state instead.
 */
export function formatExpiresIn(expiresAtMs: number, now: Date = new Date()): string | null {
  const remainingMs = expiresAtMs - now.getTime();
  if (remainingMs <= 0) return null;
  const seconds = Math.ceil(remainingMs / 1000);
  if (seconds < 60) return `Expire dans ${seconds} s`;
  return `Expire dans ${Math.ceil(seconds / 60)} min`;
}
