/**
 * Fleet liveness reader (RFC-001 §4.5, A2/A4).
 *
 * Reads `mosaic.presence` heartbeats from the fleet presence room and computes
 * deterministic online/away/offline for every agent. This is the surface a
 * human (or the escalation watchdog, P2+) reads to answer "who's alive?".
 */

import { computeFleetLiveness } from './liveness.js';
import type { MinimalMatrixClient } from './matrix-client.js';
import { DEFAULT_LIVENESS_POLICY, type AgentLiveness, type LivenessPolicy } from './types.js';

export interface FleetLivenessReaderOptions {
  client: MinimalMatrixClient;
  /** The fleet presence room (id or resolved id). */
  roomId: string;
  policy?: LivenessPolicy;
  /** Injectable clock for tests. Default Date.now. */
  now?: () => number;
  /** How many timeline events to scan back. Default 200. */
  scanLimit?: number;
}

export class FleetLivenessReader {
  private readonly policy: LivenessPolicy;
  private readonly now: () => number;

  constructor(private readonly opts: FleetLivenessReaderOptions) {
    this.policy = opts.policy ?? DEFAULT_LIVENESS_POLICY;
    this.now = opts.now ?? Date.now;
  }

  /** Read the room and compute current liveness for every seen agent. */
  async read(): Promise<AgentLiveness[]> {
    const observations = await this.opts.client.readHeartbeats(
      this.opts.roomId,
      this.opts.scanLimit ?? 200,
    );
    return computeFleetLiveness(observations, this.now(), this.policy);
  }

  /** A compact human-readable liveness board (A4 CLI view). */
  async formatBoard(): Promise<string> {
    const rows = await this.read();
    rows.sort((a, b) => a.slug.localeCompare(b.slug));
    const dot: Record<string, string> = { online: '🟢', away: '🟡', offline: '🔴' };
    const lines = rows.map(
      (r) =>
        `${dot[r.status] ?? '⚪'} ${r.slug.padEnd(16)} ${r.status.padEnd(8)} ` +
        `age=${(r.ageMs / 1000).toFixed(1)}s seq=${r.lastSeq} ${r.mxid}`,
    );
    const summary =
      `online=${rows.filter((r) => r.status === 'online').length} ` +
      `away=${rows.filter((r) => r.status === 'away').length} ` +
      `offline=${rows.filter((r) => r.status === 'offline').length}`;
    return [`Fleet presence — ${summary}`, ...lines].join('\n');
  }
}
