import { randomUUID } from "node:crypto";
import { appendFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";

// Append-only archive of every posted message. The in-memory queues are
// consume-once (read() drains the inbox) and vanish on restart, so this is
// the only durable, full-body record of relay traffic. One JSON object per
// line; never truncated.
const LOG_PATH = join(dirname(fileURLToPath(import.meta.url)), "relay-log.jsonl");

export type Role = "pm" | "dev-a" | "dev-b" | "dev-c" | "dev-d" | "dev-e" | "dev-f";
export type MessageKind = "status" | "question" | "directive" | "free";

export interface RelayMessage {
  id: string;
  from: Role;
  to: Role;
  kind: MessageKind;
  body: string;
  ts: string;
}

const KNOWN_ROLES = new Set<string>(["pm", "dev-a", "dev-b", "dev-c", "dev-d", "dev-e", "dev-f"]);

export function isRole(s: string): s is Role {
  return KNOWN_ROLES.has(s);
}

export class RelayQueue {
  private readonly queues = new Map<Role, RelayMessage[]>([
    ["pm", []],
    ["dev-a", []],
    ["dev-b", []],
    ["dev-c", []],
    ["dev-d", []],
    ["dev-e", []],
    ["dev-f", []],
  ]);

  post(from: Role, to: Role, kind: MessageKind, body: string): RelayMessage {
    const msg: RelayMessage = {
      id: randomUUID(),
      from,
      to,
      kind,
      body,
      ts: new Date().toISOString(),
    };
    this.queues.get(to)!.push(msg);
    try {
      appendFileSync(LOG_PATH, JSON.stringify(msg) + "\n");
    } catch {
      // Logging is best-effort; never let a disk error drop a message.
    }
    return msg;
  }

  read(forRole: Role): RelayMessage[] {
    const inbox = this.queues.get(forRole)!;
    const messages = [...inbox];
    inbox.length = 0;
    return messages;
  }

  pending(forRole: Role): { count: number; kinds: MessageKind[] } {
    const inbox = this.queues.get(forRole)!;
    return {
      count: inbox.length,
      kinds: inbox.map((m) => m.kind),
    };
  }
}
