/**
 * 租户端口管理器
 * 集成租户识别系统和端口管理系统
 */

import { getTenantId } from '@/utils/domain';
import { getTenantInfo } from '@/api/layout';
import { PortManager, type PortConfig } from './port-manager';
import { portStrategyManager, EnvironmentDetector } from './port-strategy';
import type { Environment } from './port-strategy';

// 租户端口绑定配置
export interface TenantPortBinding {
  tenantId: string | number;
  tenantCode: string;
  environment: Environment;
  assignedPort: number;
  customDomain?: string;
  isActive: boolean;
  createdAt: number;
  lastUsed: number;
  metadata: {
    projectName: string;
    version: string;
    description?: string;
  };
}

// 端口分配结果
export interface PortAllocationResult {
  success: boolean;
  port?: number;
  binding?: TenantPortBinding;
  error?: string;
  fallbackPorts?: number[];
  recommendations?: string[];
}

// 租户端口缓存管理
class TenantPortCache {
  private static readonly CACHE_KEY = 'tenant-port-bindings';
  private static readonly CACHE_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7天

  static get(): Map<string, TenantPortBinding> {
    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(
        ([_, binding]: [string, any]) =>
          now - binding.lastUsed < this.CACHE_EXPIRY
      );

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

  static set(cache: Map<string, TenantPortBinding>): 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 generateKey(tenantId: string | number, environment: Environment): string {
    return `${tenantId}-${environment}`;
  }
}

// 租户端口管理器
export class TenantPortManager {
  private portManager: PortManager;
  private bindings: Map<string, TenantPortBinding>;
  private currentEnvironment: Environment;

  constructor() {
    this.portManager = new PortManager();
    this.bindings = TenantPortCache.get();
    this.currentEnvironment = EnvironmentDetector.detectEnvironment();

    console.log('🏢 租户端口管理器初始化完成', {
      environment: this.currentEnvironment,
      bindingsCount: this.bindings.size
    });
  }

  /**
   * 为租户分配端口（主要方法）
   */
  async allocatePortForTenant(options?: {
    tenantId?: string | number;
    preferredPort?: number;
    forceNew?: boolean;
  }): Promise<PortAllocationResult> {
    try {
      // 1. 获取租户信息
      const tenantId = options?.tenantId || await getTenantId();
      const tenantInfo = await getTenantInfo();

      if (!tenantId) {
        return {
          success: false,
          error: '无法获取租户ID',
          recommendations: ['请检查租户配置', '确保已正确设置租户识别']
        };
      }

      // 2. 检查现有绑定
      const bindingKey = TenantPortCache.generateKey(tenantId, this.currentEnvironment);
      const existingBinding = this.bindings.get(bindingKey);

      if (existingBinding && !options?.forceNew) {
        // 验证现有端口是否仍然可用
        if (await this.validatePortBinding(existingBinding)) {
          existingBinding.lastUsed = Date.now();
          this.updateBinding(bindingKey, existingBinding);

          console.log('📋 使用现有租户端口绑定:', existingBinding.assignedPort);
          return {
            success: true,
            port: existingBinding.assignedPort,
            binding: existingBinding
          };
        } else {
          console.warn('⚠️ 现有端口绑定已失效，重新分配');
          this.bindings.delete(bindingKey);
        }
      }

      // 3. 分配新端口
      const portConfig = await this.portManager.getRecommendedPort({
        tenantId,
        projectName: tenantInfo?.name || 'mp-vue',
        preferredPort: options?.preferredPort
      });

      // 4. 创建租户端口绑定
      const binding = this.createTenantBinding(tenantId, tenantInfo, portConfig);
      this.updateBinding(bindingKey, binding);

      console.log('🎯 为租户分配新端口:', {
        tenantId,
        port: binding.assignedPort,
        environment: this.currentEnvironment
      });

      return {
        success: true,
        port: binding.assignedPort,
        binding,
        recommendations: this.generateRecommendations(binding)
      };

    } catch (error) {
      console.error('❌ 租户端口分配失败:', error);
      return {
        success: false,
        error: error instanceof Error ? error.message : '未知错误',
        recommendations: ['检查网络连接', '验证租户配置', '尝试重新启动服务']
      };
    }
  }

  /**
   * 验证端口绑定是否有效
   */
  private async validatePortBinding(binding: TenantPortBinding): Promise<boolean> {
    try {
      // 检查端口是否仍然可用
      const response = await fetch(`http://localhost:${binding.assignedPort}`, {
        method: 'HEAD',
        mode: 'no-cors',
        signal: AbortSignal.timeout(2000)
      });

      // 如果能连接，说明端口被占用（可能是我们自己的服务）
      return true;
    } catch (error) {
      // 连接失败，端口可能已释放
      return false;
    }
  }

  /**
   * 创建租户端口绑定
   */
  private createTenantBinding(
    tenantId: string | number,
    tenantInfo: any,
    portConfig: PortConfig
  ): TenantPortBinding {
    return {
      tenantId,
      tenantCode: tenantInfo?.code || String(tenantId),
      environment: this.currentEnvironment,
      assignedPort: portConfig.port,
      customDomain: tenantInfo?.domain,
      isActive: true,
      createdAt: Date.now(),
      lastUsed: Date.now(),
      metadata: {
        projectName: portConfig.projectName || 'mp-vue',
        version: '1.0.0',
        description: `${tenantInfo?.name || '租户'} - ${this.currentEnvironment}环境`
      }
    };
  }

  /**
   * 更新绑定缓存
   */
  private updateBinding(key: string, binding: TenantPortBinding): void {
    this.bindings.set(key, binding);
    TenantPortCache.set(this.bindings);
  }

  /**
   * 生成建议
   */
  private generateRecommendations(binding: TenantPortBinding): string[] {
    const recommendations: string[] = [];
    const strategy = portStrategyManager.getCurrentStrategy();

    // 环境特定建议
    switch (binding.environment) {
      case 'development':
        recommendations.push('开发环境：建议配置热重载和调试工具');
        recommendations.push(`访问地址：http://localhost:${binding.assignedPort}`);
        break;
      case 'test':
        recommendations.push('测试环境：建议配置自动化测试和监控');
        break;
      case 'production':
        recommendations.push('生产环境：建议配置HTTPS和负载均衡');
        if (binding.customDomain) {
          recommendations.push(`自定义域名：${binding.customDomain}`);
        }
        break;
    }

    // 端口范围建议
    if (binding.assignedPort < strategy.portRange[0] || binding.assignedPort > strategy.portRange[1]) {
      recommendations.push('⚠️ 分配的端口超出推荐范围，可能存在冲突风险');
    }

    return recommendations;
  }

  /**
   * 获取租户端口信息
   */
  async getTenantPortInfo(tenantId?: string | number): Promise<{
    current?: TenantPortBinding;
    history: TenantPortBinding[];
    recommendations: string[];
  }> {
    const targetTenantId = tenantId || await getTenantId();
    const history: TenantPortBinding[] = [];
    let current: TenantPortBinding | undefined;

    // 查找当前和历史绑定
    this.bindings.forEach(binding => {
      if (binding.tenantId === targetTenantId) {
        if (binding.environment === this.currentEnvironment && binding.isActive) {
          current = binding;
        }
        history.push(binding);
      }
    });

    // 按时间排序
    history.sort((a, b) => b.lastUsed - a.lastUsed);

    const recommendations = current
      ? this.generateRecommendations(current)
      : ['当前环境暂无端口绑定，建议调用 allocatePortForTenant 分配端口'];

    return { current, history, recommendations };
  }

  /**
   * 释放租户端口
   */
  async releaseTenantPort(tenantId?: string | number): Promise<boolean> {
    try {
      const targetTenantId = tenantId || await getTenantId();
      const bindingKey = TenantPortCache.generateKey(targetTenantId, this.currentEnvironment);

      const binding = this.bindings.get(bindingKey);
      if (binding) {
        binding.isActive = false;
        this.updateBinding(bindingKey, binding);
        console.log(`🔓 已释放租户 ${targetTenantId} 的端口 ${binding.assignedPort}`);
        return true;
      }

      return false;
    } catch (error) {
      console.error('释放租户端口失败:', error);
      return false;
    }
  }

  /**
   * 获取所有租户端口统计
   */
  getAllTenantsPortStats(): {
    totalBindings: number;
    activeBindings: number;
    environmentStats: Record<Environment, number>;
    portRangeUsage: { min: number; max: number; average: number };
    topTenants: Array<{ tenantId: string | number; bindingsCount: number }>;
  } {
    const stats = {
      totalBindings: this.bindings.size,
      activeBindings: 0,
      environmentStats: {} as Record<Environment, number>,
      portRangeUsage: { min: Infinity, max: 0, average: 0 },
      topTenants: [] as Array<{ tenantId: string | number; bindingsCount: number }>
    };

    const tenantCounts = new Map<string | number, number>();
    let portSum = 0;

    this.bindings.forEach(binding => {
      // 活跃绑定统计
      if (binding.isActive) {
        stats.activeBindings++;
      }

      // 环境统计
      stats.environmentStats[binding.environment] =
        (stats.environmentStats[binding.environment] || 0) + 1;

      // 端口范围统计
      stats.portRangeUsage.min = Math.min(stats.portRangeUsage.min, binding.assignedPort);
      stats.portRangeUsage.max = Math.max(stats.portRangeUsage.max, binding.assignedPort);
      portSum += binding.assignedPort;

      // 租户统计
      const count = tenantCounts.get(binding.tenantId) || 0;
      tenantCounts.set(binding.tenantId, count + 1);
    });

    // 计算平均端口
    stats.portRangeUsage.average = stats.totalBindings > 0
      ? Math.round(portSum / stats.totalBindings)
      : 0;

    // 修复无限大的情况
    if (stats.portRangeUsage.min === Infinity) {
      stats.portRangeUsage.min = 0;
    }

    // 排序租户使用量
    stats.topTenants = Array.from(tenantCounts.entries())
      .map(([tenantId, count]) => ({ tenantId, bindingsCount: count }))
      .sort((a, b) => b.bindingsCount - a.bindingsCount)
      .slice(0, 10);

    return stats;
  }

  /**
   * 清理过期绑定
   */
  cleanupExpiredBindings(): number {
    const now = Date.now();
    const expiry = 7 * 24 * 60 * 60 * 1000; // 7天
    let cleaned = 0;

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

    if (cleaned > 0) {
      TenantPortCache.set(this.bindings);
      console.log(`🧹 清理了 ${cleaned} 个过期的租户端口绑定`);
    }

    return cleaned;
  }

  /**
   * 重置所有绑定
   */
  resetAllBindings(): void {
    this.bindings.clear();
    TenantPortCache.clear();
    console.log('🔄 所有租户端口绑定已重置');
  }
}

// 导出默认实例
export const tenantPortManager = new TenantPortManager();
