import * as plugins from './plugins.js';
import type { IDomainConfig, IPortProxySettings } from './classes.pp.interfaces.js';

/**
 * Manages domain configurations and target selection
 */
export class DomainConfigManager {
  // Track round-robin indices for domain configs
  private domainTargetIndices: Map<IDomainConfig, number> = new Map();
  
  constructor(private settings: IPortProxySettings) {}
  
  /**
   * Updates the domain configurations
   */
  public updateDomainConfigs(newDomainConfigs: IDomainConfig[]): void {
    this.settings.domainConfigs = newDomainConfigs;
    
    // Reset target indices for removed configs
    const currentConfigSet = new Set(newDomainConfigs);
    for (const [config] of this.domainTargetIndices) {
      if (!currentConfigSet.has(config)) {
        this.domainTargetIndices.delete(config);
      }
    }
  }
  
  /**
   * Get all domain configurations
   */
  public getDomainConfigs(): IDomainConfig[] {
    return this.settings.domainConfigs;
  }
  
  /**
   * Find domain config matching a server name
   */
  public findDomainConfig(serverName: string): IDomainConfig | undefined {
    if (!serverName) return undefined;
    
    return this.settings.domainConfigs.find((config) =>
      config.domains.some((d) => plugins.minimatch(serverName, d))
    );
  }
  
  /**
   * Find domain config for a specific port
   */
  public findDomainConfigForPort(port: number): IDomainConfig | undefined {
    return this.settings.domainConfigs.find(
      (domain) =>
        domain.portRanges &&
        domain.portRanges.length > 0 &&
        this.isPortInRanges(port, domain.portRanges)
    );
  }
  
  /**
   * Check if a port is within any of the given ranges
   */
  public isPortInRanges(port: number, ranges: Array<{ from: number; to: number }>): boolean {
    return ranges.some((range) => port >= range.from && port <= range.to);
  }
  
  /**
   * Get target IP with round-robin support
   */
  public getTargetIP(domainConfig: IDomainConfig): string {
    if (domainConfig.targetIPs && domainConfig.targetIPs.length > 0) {
      const currentIndex = this.domainTargetIndices.get(domainConfig) || 0;
      const ip = domainConfig.targetIPs[currentIndex % domainConfig.targetIPs.length];
      this.domainTargetIndices.set(domainConfig, currentIndex + 1);
      return ip;
    }
    
    return this.settings.targetIP || 'localhost';
  }
  
  /**
   * Checks if a domain should use NetworkProxy
   */
  public shouldUseNetworkProxy(domainConfig: IDomainConfig): boolean {
    return !!domainConfig.useNetworkProxy;
  }
  
  /**
   * Gets the NetworkProxy port for a domain
   */
  public getNetworkProxyPort(domainConfig: IDomainConfig): number | undefined {
    return domainConfig.useNetworkProxy 
      ? (domainConfig.networkProxyPort || this.settings.networkProxyPort)
      : undefined;
  }
  
  /**
   * Get effective allowed and blocked IPs for a domain
   */
  public getEffectiveIPRules(domainConfig: IDomainConfig): {
    allowedIPs: string[],
    blockedIPs: string[]
  } {
    return {
      allowedIPs: [
        ...domainConfig.allowedIPs,
        ...(this.settings.defaultAllowedIPs || [])
      ],
      blockedIPs: [
        ...(domainConfig.blockedIPs || []),
        ...(this.settings.defaultBlockedIPs || [])
      ]
    };
  }
  
  /**
   * Get connection timeout for a domain
   */
  public getConnectionTimeout(domainConfig?: IDomainConfig): number {
    if (domainConfig?.connectionTimeout) {
      return domainConfig.connectionTimeout;
    }
    return this.settings.maxConnectionLifetime || 86400000; // 24 hours default
  }
}