/**
 * @module QueueManager
 * @description Interface and types for managing event queues in the A2A protocol
 * 
 * This module provides interfaces and types for managing the lifecycle of event
 * queues in the A2A protocol server. It defines the QueueManager interface and
 * related types for queue statistics and errors.
 */

import { EventQueue } from '../agent-execution/event-queue';
import { A2AError, ERROR_CODES } from '@dexwox-labs/a2a-core';

/**
 * Interface for managing event queue lifecycles
 * 
 * The QueueManager interface defines the contract for managing event queues
 * in the A2A protocol server. It provides methods for creating, retrieving,
 * tapping into, and closing event queues for tasks.
 * 
 * @example
 * ```typescript
 * // Create a queue manager
 * const queueManager = new InMemoryQueueManager();
 * 
 * // Create or get a queue for a task
 * const queue = await queueManager.createOrGet('task-123');
 * 
 * // Subscribe to events on the queue
 * queue.subscribe(event => {
 *   console.log(`Event: ${event.type} for task ${event.task.id}`);
 * });
 * 
 * // Tap into the queue to create a new consumer
 * const tapQueue = await queueManager.tap('task-123');
 * 
 * // Close the queue when done
 * await queueManager.close('task-123');
 * ```
 */
export interface QueueManager {
  /**
   * Adds a new queue for a task
   * 
   * This method registers a new event queue for a specific task.
   * It throws an error if a queue already exists for the task.
   * 
   * @param taskId - ID of the task to add a queue for
   * @param queue - The event queue to add
   * @returns Promise that resolves when the queue is added
   * @throws {QueueExistsError} If a queue already exists for the task
   * 
   * @example
   * ```typescript
   * const queue = new EventQueue();
   * try {
   *   await queueManager.add('task-123', queue);
   *   console.log('Queue added successfully');
   * } catch (error) {
   *   if (error instanceof QueueExistsError) {
   *     console.error('Queue already exists for this task');
   *   }
   * }
   * ```
   */
  add(taskId: string, queue: EventQueue): Promise<void>;

  /**
   * Gets an existing queue for a task
   * 
   * This method retrieves the event queue for a specific task.
   * It returns undefined if no queue exists for the task.
   * 
   * @param taskId - ID of the task to get the queue for
   * @returns Promise resolving to the event queue, or undefined if not found
   * 
   * @example
   * ```typescript
   * const queue = await queueManager.get('task-123');
   * if (queue) {
   *   console.log('Found queue for task');
   *   // Use the queue
   * } else {
   *   console.log('No queue found for task');
   * }
   * ```
   */
  get(taskId: string): Promise<EventQueue | undefined>;

  /**
   * Creates a new queue or gets an existing one
   * 
   * This method retrieves the event queue for a specific task if it exists,
   * or creates a new one if it doesn't. It's a convenience method that
   * combines the functionality of add and get.
   * 
   * @param taskId - ID of the task to get or create a queue for
   * @returns Promise resolving to the existing or newly created event queue
   * 
   * @example
   * ```typescript
   * // Get or create a queue for a task
   * const queue = await queueManager.createOrGet('task-123');
   * 
   * // Use the queue
   * queue.subscribe(event => {
   *   console.log(`Received event: ${event.type}`);
   * });
   * ```
   */
  createOrGet(taskId: string): Promise<EventQueue>;

  /**
   * Taps into an existing queue to create a new consumer
   * 
   * This method creates a new event queue that receives copies of all events
   * published to the original queue for a specific task. It's useful for
   * creating specialized event handlers or for filtering events.
   * 
   * @param taskId - ID of the task to tap the queue for
   * @returns Promise resolving to a new event queue that receives copies of events
   * @throws {NoQueueError} If no queue exists for the task
   * 
   * @example
   * ```typescript
   * try {
   *   // Create a specialized queue for completed tasks
   *   const tapQueue = await queueManager.tap('task-123');
   *   
   *   // Subscribe to events on the tapped queue
   *   tapQueue.subscribe(event => {
   *     if (event.type === 'taskCompleted') {
   *       // Handle completed tasks
   *       console.log('Task completed:', event.task.id);
   *     }
   *   });
   * } catch (error) {
   *   if (error instanceof NoQueueError) {
   *     console.error('No queue exists for this task');
   *   }
   * }
   * ```
   */
  tap(taskId: string): Promise<EventQueue>;

  /**
   * Closes and removes a queue
   * 
   * This method shuts down the event queue for a specific task and removes
   * it from the manager. After calling this method, the queue will no longer
   * receive or publish events.
   * 
   * @param taskId - ID of the task to close the queue for
   * @returns Promise that resolves when the queue is closed and removed
   * 
   * @example
   * ```typescript
   * // When done with a task's queue
   * await queueManager.close('task-123');
   * console.log('Queue closed and removed');
   * ```
   */
  close(taskId: string): Promise<void>;

  /**
   * Gets statistics for a queue
   * 
   * This method retrieves statistics about the event queue for a specific task,
   * such as the number of events, consumers, and performance metrics.
   * 
   * @param taskId - ID of the task to get queue statistics for
   * @returns Promise resolving to queue statistics
   * 
   * @example
   * ```typescript
   * const stats = await queueManager.getStats('task-123');
   * console.log('Queue size:', stats.size);
   * console.log('Number of consumers:', stats.consumers);
   * console.log('Events processed:', stats.processed);
   * console.log('Error rate:', stats.errorRate);
   * ```
   */
  getStats(taskId: string): Promise<QueueStats>;
}

/**
 * Statistics for an event queue
 * 
 * This interface defines the structure of statistics for an event queue,
 * including metrics about queue size, consumers, processing performance,
 * and error rates.
 */
export interface QueueStats {
  /** Current number of events in the queue */
  size: number;
  
  /** Number of consumers subscribed to the queue */
  consumers: number;
  
  /** Total number of events processed by the queue */
  processed: number;
  
  /** Number of events that failed processing */
  failed: number;
  
  /** Timestamp of the last activity on the queue */
  lastActivity: Date;
  
  /** Events processed per second */
  throughput: number;
  
  /** Average time to process an event in milliseconds */
  avgProcessingTime: number;
  
  /** Ratio of failed events to total processed events */
  errorRate: number;
}

/**
 * Error thrown when attempting to add a queue that already exists
 * 
 * This error is thrown when trying to add a new queue for a task that
 * already has a queue registered with the queue manager.
 * 
 * @example
 * ```typescript
 * try {
 *   await queueManager.add('task-123', new EventQueue());
 * } catch (error) {
 *   if (error instanceof QueueExistsError) {
 *     console.error('Cannot add queue:', error.message);
 *   }
 * }
 * ```
 */
export class QueueExistsError extends A2AError {
  /**
   * Creates a new QueueExistsError
   * 
   * @param taskId - ID of the task that already has a queue
   */
  constructor(taskId: string) {
    super(`Queue already exists for task ${taskId}`, ERROR_CODES.QUEUE_EXISTS);
  }
}

/**
 * Error thrown when attempting to access a queue that doesn't exist
 * 
 * This error is thrown when trying to access or tap into a queue for a task
 * that doesn't have a queue registered with the queue manager.
 * 
 * @example
 * ```typescript
 * try {
 *   await queueManager.tap('task-123');
 * } catch (error) {
 *   if (error instanceof NoQueueError) {
 *     console.error('Cannot tap queue:', error.message);
 *   }
 * }
 * ```
 */
export class NoQueueError extends A2AError {
  /**
   * Creates a new NoQueueError
   * 
   * @param taskId - ID of the task that doesn't have a queue
   */
  constructor(taskId: string) {
    super(`No queue exists for task ${taskId}`, ERROR_CODES.NO_QUEUE);
  }
}
