import { createHash } from 'node:crypto';

/** Stable device fingerprint from OS hostname + arch. Frozen on first run (caller persists it). Pure. */
export function deviceIdFrom(hostname: string, arch: string): string {
  return createHash('sha256').update(`${hostname}|${arch}`).digest('hex').slice(0, 16);
}

export interface CachedLicense {
  valid: boolean;
  plan: string; // 'paid' | 'trial' | 'admin'
  expiresAt: string | null; // ISO, or null = no expiry
  lastValidatedMs: number; // epoch ms of last successful server validation
}
export type Gate = 'unlocked' | 'locked';

/** Decide whether the app is usable, from the cached license + offline grace. Pure. */
export function licenseGate(
  cache: CachedLicense | null,
  nowMs: number,
  cfg: { offlineGraceDays: number },
): Gate {
  if (!cache || !cache.valid) return 'locked';
  if (cache.expiresAt) {
    const exp = new Date(cache.expiresAt).getTime();
    // Unparseable expiry (NaN) must fail CLOSED — otherwise `now > NaN` is false and a
    // garbage/corrupt expiry would silently pass the expiry check.
    if (Number.isNaN(exp) || nowMs > exp) return 'locked';
  }
  if (nowMs - cache.lastValidatedMs > cfg.offlineGraceDays * 86_400_000) return 'locked';
  return 'unlocked';
}
