import type { SSEEvent } from './types/agents.js';

type Listener = (event: SSEEvent) => void;

interface PipelineSession {
  history: SSEEvent[];
  listeners: Set<Listener>;
  terminal: boolean;
  cleanupTimer: NodeJS.Timeout | null;
}

const sessions = new Map<string, PipelineSession>();
const CLEANUP_DELAY_MS = 10 * 60 * 1000;

function getOrCreateSession(recId: string): PipelineSession {
  const existing = sessions.get(recId);
  if (existing) {
    if (existing.cleanupTimer) {
      clearTimeout(existing.cleanupTimer);
      existing.cleanupTimer = null;
    }
    return existing;
  }

  const session: PipelineSession = {
    history: [],
    listeners: new Set(),
    terminal: false,
    cleanupTimer: null,
  };
  sessions.set(recId, session);
  return session;
}

function scheduleCleanup(recId: string, session: PipelineSession): void {
  if (session.cleanupTimer) {
    clearTimeout(session.cleanupTimer);
  }

  session.cleanupTimer = setTimeout(() => {
    const current = sessions.get(recId);
    if (current === session && current.listeners.size === 0) {
      sessions.delete(recId);
    }
  }, CLEANUP_DELAY_MS);
}

export function resetPipelineSession(recId: string): void {
  const existing = sessions.get(recId);
  if (existing?.cleanupTimer) {
    clearTimeout(existing.cleanupTimer);
  }
  sessions.delete(recId);
}

export function publishPipelineEvent(recId: string, event: SSEEvent): void {
  const session = getOrCreateSession(recId);
  session.history.push(event);

  for (const listener of session.listeners) {
    listener(event);
  }

  if (event.stage === 'complete' || event.status === 'error') {
    session.terminal = true;
    if (session.listeners.size === 0) {
      scheduleCleanup(recId, session);
    }
  }
}

export function getPipelineHistory(recId: string): SSEEvent[] {
  return sessions.get(recId)?.history ?? [];
}

export function hasPipelineSession(recId: string): boolean {
  return sessions.has(recId);
}

export function subscribeToPipelineEvents(recId: string, listener: Listener): () => void {
  const session = getOrCreateSession(recId);
  session.listeners.add(listener);

  return () => {
    const current = sessions.get(recId);
    if (!current) return;

    current.listeners.delete(listener);
    if (current.terminal && current.listeners.size === 0) {
      scheduleCleanup(recId, current);
    }
  };
}
