/**
 * LANE-UI — reading the bandwidth economy (pure; see power.test.ts).
 *
 * Four states, and the distinction between the middle two is the whole point:
 *
 *   ok       draw comfortably under generation
 *   tight    draw ≥ 85% of generation — nothing is wrong yet, but there's no headroom
 *   reserve  draw EXCEEDS generation and the buffer tanks are covering the difference.
 *            This is the factory working as designed. Round 1-3 painted it as BROWNOUT,
 *            which was a lie: the sim's flag was false, THE SCREEN was calm, and only the
 *            HUD was screaming. Survival is not failure.
 *   brownout the sim says so. That flag is the only truth here — the tanks are dry and
 *            the sector is a still life.
 *
 * Units (contracts v3 ruling): `gen`/`draw` are bandwidth per SECOND, `stored` is
 * bandwidth-SECONDS. So `stored / (draw - gen)` is literally seconds of reserve left —
 * the same arithmetic LANE-SCREEN drives its dread with.
 */
import type { SimSnapshot } from '../contracts';

export type PowerState = 'ok' | 'tight' | 'reserve' | 'brownout';

/** Draw at or above this share of generation is "tight" — a warning, not a fault. */
export const TIGHT_AT = 0.85;

export interface PowerReadout {
  state: PowerState;
  /** draw/gen, clamped for the meter fill. Infinity when drawing with no generation. */
  ratio: number;
  /** Seconds of reserve left; only meaningful in the 'reserve' state. */
  reserveSeconds: number | null;
}

export function powerState(bw: SimSnapshot['bandwidth']): PowerReadout {
  const { gen, draw, stored, brownout } = bw;

  // With no generation at all, any draw is already past budget.
  const ratio = gen > 0 ? draw / gen : draw > 0 ? Infinity : 0;

  // The sim owns this word. If it says brownout, it's a brownout, whatever the maths say.
  if (brownout) return { state: 'brownout', ratio, reserveSeconds: 0 };

  const deficit = draw - gen;
  if (deficit > 0) {
    // Covered deficit: the tanks are doing exactly what tanks are for.
    const seconds = deficit > 0 ? stored / deficit : Infinity;
    return { state: 'reserve', ratio, reserveSeconds: Math.max(0, seconds) };
  }

  if (ratio >= TIGHT_AT) return { state: 'tight', ratio, reserveSeconds: null };
  return { state: 'ok', ratio, reserveSeconds: null };
}

/** "34s" — floored, because a countdown that rounds up lies at the end. */
export function formatReserve(seconds: number): string {
  if (!Number.isFinite(seconds)) return '∞';
  if (seconds >= 999) return '999s';
  return `${Math.floor(seconds)}s`;
}
