import type { SessionRoutingState } from "../protocol/decision.js";

export type SessionRouterStoreOptions = {
  capacity?: number;
  ttlMs?: number;
  now?: () => number;
};

const DEFAULT_CAPACITY = 500;
const DEFAULT_TTL_MS = 60 * 60 * 1000;

type Slot = {
  key: string;
  state: SessionRoutingState;
  expiresAt: number;
};

export class SessionRouterStore {
  private readonly capacity: number;
  private readonly ttlMs: number;
  private readonly now: () => number;
  private readonly map = new Map<string, Slot>();

  constructor(options: SessionRouterStoreOptions = {}) {
    this.capacity = Math.max(1, options.capacity ?? DEFAULT_CAPACITY);
    this.ttlMs = Math.max(1, options.ttlMs ?? DEFAULT_TTL_MS);
    this.now = options.now ?? (() => Date.now());
  }

  get(sessionId: string, isSubagent: boolean): SessionRoutingState | undefined {
    const key = makeKey(sessionId, isSubagent);
    const slot = this.map.get(key);
    if (!slot) {
      return undefined;
    }
    if (slot.expiresAt < this.now()) {
      this.map.delete(key);
      return undefined;
    }
    this.map.delete(key);
    this.map.set(key, slot);
    return slot.state;
  }

  set(state: SessionRoutingState): void {
    const key = makeKey(state.sessionId, state.isSubagent);
    const slot: Slot = {
      key,
      state,
      expiresAt: this.now() + this.ttlMs,
    };
    if (this.map.has(key)) {
      this.map.delete(key);
    } else {
      while (this.map.size >= this.capacity) {
        const oldestKey = this.map.keys().next().value;
        if (oldestKey === undefined) {
          break;
        }
        this.map.delete(oldestKey);
      }
    }
    this.map.set(key, slot);
  }

  delete(sessionId: string, isSubagent: boolean): void {
    this.map.delete(makeKey(sessionId, isSubagent));
  }

  size(): number {
    return this.map.size;
  }

  clear(): void {
    this.map.clear();
  }
}

function makeKey(sessionId: string, isSubagent: boolean): string {
  return isSubagent ? `${sessionId}:sub` : sessionId;
}