/**
 * 智能端口管理系统
 * 类似租户识别系统的端口管理解决方案
 */

import { getTenantId } from '@/utils/domain';

// 端口配置接口
export interface PortConfig {
  port: number;
  host: string;
  protocol: 'http' | 'https';
  environment: 'development' | 'test' | 'production';
  tenantId?: string | number;
  projectName?: string;
  lastUsed: number;
  isAvailable: boolean;
}

// 端口分配策略
export interface PortStrategy {
  basePort: number;
  portRange: [number, number];
  tenantOffset: number;
  environmentOffset: number;
  maxRetries: number;
}

// 端口缓存管理
class PortCache {
  private static readonly CACHE_KEY = 'port-manager-cache';
  private static readonly CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 24小时

  static get(): Map<string, PortConfig> {
    try {
      const cached = localStorage.getItem(this.CACHE_KEY);
      if (!cached) return new Map();

      const data = JSON.parse(cached);
      const now = Date.now();

      // 清理过期缓存
      const validEntries = Object.entries(data).filter(
        ([_, config]: [string, any]) =>
          now - config.lastUsed < this.CACHE_EXPIRY
      );

      return new Map(validEntries);
    } catch (error) {
      console.warn('端口缓存读取失败:', error);
      return new Map();
    }
  }

  static set(cache: Map<string, PortConfig>): void {
    try {
      const data = Object.fromEntries(cache);
      localStorage.setItem(this.CACHE_KEY, JSON.stringify(data));
    } catch (error) {
      console.warn('端口缓存保存失败:', error);
    }
  }

  static clear(): void {
    localStorage.removeItem(this.CACHE_KEY);
  }

  static getStats(): { total: number; expired: number; active: number } {
    const cache = this.get();
    const now = Date.now();
    let expired = 0;
    let active = 0;

    cache.forEach(config => {
      if (now - config.lastUsed > this.CACHE_EXPIRY) {
        expired++;
      } else {
        active++;
      }
    });

    return { total: cache.size, expired, active };
  }
}

// 端口工具函数
class PortUtils {
  /**
   * 检查端口是否可用
   */
  static async isPortAvailable(port: number, host: string = 'localhost'): Promise<boolean> {
    try {
      // 在浏览器环境中，我们无法直接检测端口占用
      // 这里使用一个模拟的检测方法
      const response = await fetch(`http://${host}:${port}`, {
        method: 'HEAD',
        mode: 'no-cors',
        signal: AbortSignal.timeout(1000)
      });

      // 如果能连接到端口，说明端口被占用
      return false;
    } catch (error) {
      // 连接失败，说明端口可用
      return true;
    }
  }

  /**
   * 获取端口范围内的可用端口
   */
  static async findAvailablePort(
    startPort: number,
    endPort: number,
    host: string = 'localhost'
  ): Promise<number | null> {
    for (let port = startPort; port <= endPort; port++) {
      if (await this.isPortAvailable(port, host)) {
        return port;
      }
    }
    return null;
  }

  /**
   * 生成端口键
   */
  static generatePortKey(
    tenantId: string | number,
    environment: string,
    projectName?: string
  ): string {
    const parts = [tenantId, environment];
    if (projectName) parts.push(projectName);
    return parts.join('-');
  }

  /**
   * 计算租户端口偏移
   */
  static calculateTenantOffset(tenantId: string | number): number {
    const id = typeof tenantId === 'string' ? parseInt(tenantId) || 0 : tenantId;
    return (id % 1000) * 10; // 每个租户分配10个端口的空间
  }

  /**
   * 计算环境端口偏移
   */
  static calculateEnvironmentOffset(environment: string): number {
    const offsets = {
      'development': 0,
      'test': 1000,
      'production': 2000
    };
    return offsets[environment as keyof typeof offsets] || 0;
  }
}

// 智能端口管理器
export class PortManager {
  private cache: Map<string, PortConfig>;
  private strategy: PortStrategy;
  private environment: string;

  constructor(strategy?: Partial<PortStrategy>) {
    this.environment = process.env.NODE_ENV || 'development';
    this.cache = PortCache.get();

    // 默认策略
    this.strategy = {
      basePort: 3000,
      portRange: [3000, 9999],
      tenantOffset: 10,
      environmentOffset: 1000,
      maxRetries: 50,
      ...strategy
    };

    console.log('🚀 端口管理器初始化完成', {
      environment: this.environment,
      strategy: this.strategy,
      cacheSize: this.cache.size
    });
  }

  /**
   * 获取推荐端口（智能分配）
   */
  async getRecommendedPort(options?: {
    tenantId?: string | number;
    projectName?: string;
    preferredPort?: number;
  }): Promise<PortConfig> {
    const tenantId = options?.tenantId || await getTenantId();
    const projectName = options?.projectName || 'mp-vue';
    const portKey = PortUtils.generatePortKey(tenantId, this.environment, projectName);

    // 1. 检查缓存中的端口
    const cachedPort = this.cache.get(portKey);
    if (cachedPort && await PortUtils.isPortAvailable(cachedPort.port)) {
      cachedPort.lastUsed = Date.now();
      this.updateCache(portKey, cachedPort);
      console.log('📋 使用缓存端口:', cachedPort.port);
      return cachedPort;
    }

    // 2. 尝试首选端口
    if (options?.preferredPort) {
      if (await PortUtils.isPortAvailable(options.preferredPort)) {
        const config = this.createPortConfig(options.preferredPort, tenantId, projectName);
        this.updateCache(portKey, config);
        console.log('✨ 使用首选端口:', options.preferredPort);
        return config;
      }
    }

    // 3. 智能分配端口
    const recommendedPort = await this.allocateSmartPort(tenantId, projectName);
    const config = this.createPortConfig(recommendedPort, tenantId, projectName);
    this.updateCache(portKey, config);

    console.log('🎯 智能分配端口:', recommendedPort);
    return config;
  }

  /**
   * 智能端口分配算法
   */
  private async allocateSmartPort(
    tenantId: string | number,
    projectName: string
  ): Promise<number> {
    const tenantOffset = PortUtils.calculateTenantOffset(tenantId);
    const envOffset = PortUtils.calculateEnvironmentOffset(this.environment);

    // 计算推荐端口
    const recommendedPort = this.strategy.basePort + envOffset + tenantOffset;

    // 在推荐端口附近查找可用端口
    const searchRange = 20; // 在推荐端口前后20个端口范围内搜索
    const startPort = Math.max(
      recommendedPort - searchRange,
      this.strategy.portRange[0]
    );
    const endPort = Math.min(
      recommendedPort + searchRange,
      this.strategy.portRange[1]
    );

    // 优先尝试推荐端口
    if (await PortUtils.isPortAvailable(recommendedPort)) {
      return recommendedPort;
    }

    // 在范围内查找可用端口
    const availablePort = await PortUtils.findAvailablePort(startPort, endPort);
    if (availablePort) {
      return availablePort;
    }

    // 如果推荐范围内没有可用端口，扩大搜索范围
    const fallbackPort = await PortUtils.findAvailablePort(
      this.strategy.portRange[0],
      this.strategy.portRange[1]
    );

    if (fallbackPort) {
      return fallbackPort;
    }

    // 最后的备选方案
    throw new Error(`无法在端口范围 ${this.strategy.portRange[0]}-${this.strategy.portRange[1]} 内找到可用端口`);
  }

  /**
   * 创建端口配置
   */
  private createPortConfig(
    port: number,
    tenantId: string | number,
    projectName: string
  ): PortConfig {
    return {
      port,
      host: 'localhost',
      protocol: 'http',
      environment: this.environment as any,
      tenantId,
      projectName,
      lastUsed: Date.now(),
      isAvailable: true
    };
  }

  /**
   * 更新缓存
   */
  private updateCache(key: string, config: PortConfig): void {
    this.cache.set(key, config);
    PortCache.set(this.cache);
  }

  /**
   * 获取端口使用统计
   */
  getPortStats(): {
    cacheStats: ReturnType<typeof PortCache.getStats>;
    currentPorts: PortConfig[];
    strategy: PortStrategy;
  } {
    return {
      cacheStats: PortCache.getStats(),
      currentPorts: Array.from(this.cache.values()),
      strategy: this.strategy
    };
  }

  /**
   * 清理过期端口缓存
   */
  cleanupExpiredPorts(): number {
    const now = Date.now();
    const expiry = 24 * 60 * 60 * 1000; // 24小时
    let cleaned = 0;

    this.cache.forEach((config, key) => {
      if (now - config.lastUsed > expiry) {
        this.cache.delete(key);
        cleaned++;
      }
    });

    if (cleaned > 0) {
      PortCache.set(this.cache);
      console.log(`🧹 清理了 ${cleaned} 个过期端口缓存`);
    }

    return cleaned;
  }

  /**
   * 重置端口缓存
   */
  resetCache(): void {
    this.cache.clear();
    PortCache.clear();
    console.log('🔄 端口缓存已重置');
  }
}

// 导出默认实例
export const portManager = new PortManager();

// 导出工具函数
export { PortUtils, PortCache };
