import type { IRouteConfig } from './models/route-types.js';

/**
 * Global state store for ACME operations
 * Tracks active challenge routes and port allocations
 */
export class AcmeStateManager {
  private activeChallengeRoutes: Map<string, IRouteConfig> = new Map();
  private acmePortAllocations: Set<number> = new Set();
  private primaryChallengeRoute: IRouteConfig | null = null;
  
  /**
   * Check if a challenge route is active
   */
  public isChallengeRouteActive(): boolean {
    return this.activeChallengeRoutes.size > 0;
  }
  
  /**
   * Register a challenge route as active
   */
  public addChallengeRoute(route: IRouteConfig): void {
    this.activeChallengeRoutes.set(route.name, route);
    
    // Track the primary challenge route
    if (!this.primaryChallengeRoute || route.priority > (this.primaryChallengeRoute.priority || 0)) {
      this.primaryChallengeRoute = route;
    }
    
    // Track port allocations
    const ports = Array.isArray(route.match.ports) ? route.match.ports : [route.match.ports];
    ports.forEach(port => this.acmePortAllocations.add(port));
  }
  
  /**
   * Remove a challenge route
   */
  public removeChallengeRoute(routeName: string): void {
    const route = this.activeChallengeRoutes.get(routeName);
    if (!route) return;
    
    this.activeChallengeRoutes.delete(routeName);
    
    // Update primary challenge route if needed
    if (this.primaryChallengeRoute?.name === routeName) {
      this.primaryChallengeRoute = null;
      // Find new primary route with highest priority
      let highestPriority = -1;
      for (const [_, activeRoute] of this.activeChallengeRoutes) {
        const priority = activeRoute.priority || 0;
        if (priority > highestPriority) {
          highestPriority = priority;
          this.primaryChallengeRoute = activeRoute;
        }
      }
    }
    
    // Update port allocations - only remove if no other routes use this port
    const ports = Array.isArray(route.match.ports) ? route.match.ports : [route.match.ports];
    ports.forEach(port => {
      let portStillUsed = false;
      for (const [_, activeRoute] of this.activeChallengeRoutes) {
        const activePorts = Array.isArray(activeRoute.match.ports) ? 
          activeRoute.match.ports : [activeRoute.match.ports];
        if (activePorts.includes(port)) {
          portStillUsed = true;
          break;
        }
      }
      if (!portStillUsed) {
        this.acmePortAllocations.delete(port);
      }
    });
  }
  
  /**
   * Get all active challenge routes
   */
  public getActiveChallengeRoutes(): IRouteConfig[] {
    return Array.from(this.activeChallengeRoutes.values());
  }
  
  /**
   * Get the primary challenge route
   */
  public getPrimaryChallengeRoute(): IRouteConfig | null {
    return this.primaryChallengeRoute;
  }
  
  /**
   * Check if a port is allocated for ACME
   */
  public isPortAllocatedForAcme(port: number): boolean {
    return this.acmePortAllocations.has(port);
  }
  
  /**
   * Get all ACME ports
   */
  public getAcmePorts(): number[] {
    return Array.from(this.acmePortAllocations);
  }
  
  /**
   * Clear all state (for shutdown or reset)
   */
  public clear(): void {
    this.activeChallengeRoutes.clear();
    this.acmePortAllocations.clear();
    this.primaryChallengeRoute = null;
  }
}