/**
 * Handler Registry - Runtime registry for queue handlers
 * Properly located in handlers package instead of types
 */

import type {
  HandlerConfig,
  HandlerConfigWithSchedule,
  JobHandler,
  ScheduledJob,
} from '@stock-bot/types';
import { getLogger } from '@stock-bot/logger';

class HandlerRegistry {
  private readonly logger = getLogger('handler-registry');
  private handlers = new Map<string, HandlerConfig>();
  private handlerSchedules = new Map<string, ScheduledJob[]>();
  private handlerServices = new Map<string, string>(); // Maps handler to service name

  /**
   * Register a handler with its operations (simple config)
   */
  register(handlerName: string, config: HandlerConfig, serviceName?: string): void {
    this.logger.info(`Registering handler: ${handlerName}`, {
      operations: Object.keys(config),
      service: serviceName,
    });

    this.handlers.set(handlerName, config);
    
    // Track service ownership if provided
    if (serviceName) {
      this.handlerServices.set(handlerName, serviceName);
    }
  }

  /**
   * Register a handler with scheduled jobs (enhanced config)
   */
  registerWithSchedule(config: HandlerConfigWithSchedule, serviceName?: string): void {
    this.logger.info(`Registering handler with schedule: ${config.name}`, {
      operations: Object.keys(config.operations),
      scheduledJobs: config.scheduledJobs?.length || 0,
      service: serviceName,
    });

    this.handlers.set(config.name, config.operations);

    if (config.scheduledJobs && config.scheduledJobs.length > 0) {
      this.handlerSchedules.set(config.name, config.scheduledJobs);
    }
    
    // Track service ownership if provided
    if (serviceName) {
      this.handlerServices.set(config.name, serviceName);
    }
  }

  /**
   * Get a specific handler's configuration
   */
  getHandler(handlerName: string): HandlerConfig | undefined {
    return this.handlers.get(handlerName);
  }

  /**
   * Get all registered handlers
   */
  getAllHandlers(): Map<string, HandlerConfig> {
    return new Map(this.handlers);
  }

  /**
   * Get scheduled jobs for a handler
   */
  getScheduledJobs(handlerName: string): ScheduledJob[] {
    return this.handlerSchedules.get(handlerName) || [];
  }

  /**
   * Get all handlers with their scheduled jobs
   */
  getAllHandlersWithSchedule(): Map<
    string,
    { operations: HandlerConfig; scheduledJobs: ScheduledJob[] }
  > {
    const result = new Map<string, { operations: HandlerConfig; scheduledJobs: ScheduledJob[] }>();

    for (const [name, operations] of this.handlers) {
      result.set(name, {
        operations,
        scheduledJobs: this.handlerSchedules.get(name) || [],
      });
    }

    return result;
  }

  /**
   * Get a specific operation from a handler
   */
  getOperation(handlerName: string, operationName: string): JobHandler | undefined {
    const handler = this.handlers.get(handlerName);
    if (!handler) {
      return undefined;
    }
    return handler[operationName];
  }

  /**
   * Check if a handler is registered
   */
  hasHandler(handlerName: string): boolean {
    return this.handlers.has(handlerName);
  }

  /**
   * Get list of all registered handler names
   */
  getHandlerNames(): string[] {
    return Array.from(this.handlers.keys());
  }

  /**
   * Get registry statistics
   */
  getStats(): { handlers: number; operations: number; scheduledJobs: number } {
    let operationCount = 0;
    let scheduledJobCount = 0;

    for (const [_, config] of this.handlers) {
      operationCount += Object.keys(config).length;
    }

    for (const [_, jobs] of this.handlerSchedules) {
      scheduledJobCount += jobs.length;
    }

    return {
      handlers: this.handlers.size,
      operations: operationCount,
      scheduledJobs: scheduledJobCount,
    };
  }

  /**
   * Get the service that owns a handler
   */
  getHandlerService(handlerName: string): string | undefined {
    return this.handlerServices.get(handlerName);
  }

  /**
   * Get all handlers for a specific service
   */
  getServiceHandlers(serviceName: string): string[] {
    const handlers: string[] = [];
    for (const [handler, service] of this.handlerServices) {
      if (service === serviceName) {
        handlers.push(handler);
      }
    }
    return handlers;
  }

  /**
   * Set service ownership for a handler (used during auto-discovery)
   */
  setHandlerService(handlerName: string, serviceName: string): void {
    this.handlerServices.set(handlerName, serviceName);
  }

  /**
   * Clear all registrations (useful for testing)
   */
  clear(): void {
    this.handlers.clear();
    this.handlerSchedules.clear();
    this.handlerServices.clear();
  }
}

// Export singleton instance
export const handlerRegistry = new HandlerRegistry();