import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
import { EventEmitter } from 'events';
import { RateLimiterMemory } from 'rate-limiter-flexible';

/**
 * API Gateway for ZAI Microservices Architecture
 * Centralized routing, authentication, and load balancing
 */
export class APIGateway extends EventEmitter {
  constructor() {
    super();
    
    this.app = express();
    this.services = new Map();
    this.healthChecks = new Map();
    this.loadBalancers = new Map();
    
    // Rate limiting configuration
    this.rateLimiter = new RateLimiterMemory({
      keyGenerator: (req) => req.ip,
      points: 1000, // Number of requests
      duration: 60, // Per 60 seconds
    });
    
    this.setupMiddleware();
    this.setupRoutes();
    this.startHealthChecking();
    
    console.log('🌐 API Gateway initialized');
  }

  /**
   * Register a microservice
   */
  registerService(name, config) {
    const service = {
      name,
      instances: config.instances || [],
      healthEndpoint: config.healthEndpoint || '/health',
      timeout: config.timeout || 30000,
      retries: config.retries || 3,
      loadBalanceStrategy: config.loadBalanceStrategy || 'round-robin',
      currentIndex: 0
    };
    
    this.services.set(name, service);
    this.loadBalancers.set(name, this.createLoadBalancer(service));
    
    console.log(`📡 Service registered: ${name} with ${service.instances.length} instances`);
    this.emit('serviceRegistered', { name, service });
  }

  /**
   * Setup middleware
   */
  setupMiddleware() {
    // CORS
    this.app.use((req, res, next) => {
      res.header('Access-Control-Allow-Origin', '*');
      res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
      res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Admin-Key');
      if (req.method === 'OPTIONS') {
        res.sendStatus(200);
      } else {
        next();
      }
    });

    // Rate limiting
    this.app.use(async (req, res, next) => {
      try {
        await this.rateLimiter.consume(req.ip);
        next();
      } catch (rejRes) {
        res.status(429).json({ 
          error: 'Too many requests',
          retryAfter: Math.round(rejRes.msBeforeNext / 1000) || 1
        });
      }
    });

    // Request logging
    this.app.use((req, res, next) => {
      const start = Date.now();
      res.on('finish', () => {
        const duration = Date.now() - start;
        console.log(`🌐 ${req.method} ${req.path} - ${res.statusCode} (${duration}ms)`);
        
        this.emit('requestCompleted', {
          method: req.method,
          path: req.path,
          statusCode: res.statusCode,
          duration,
          ip: req.ip
        });
      });
      next();
    });

    // Body parsing
    this.app.use(express.json({ limit: '10mb' }));
    this.app.use(express.urlencoded({ extended: true }));
  }

  /**
   * Setup routes and proxies
   */
  setupRoutes() {
    // Health check for gateway itself
    this.app.get('/gateway/health', (req, res) => {
      const serviceHealth = {};
      for (const [name, health] of this.healthChecks.entries()) {
        serviceHealth[name] = health;
      }
      
      res.json({
        status: 'healthy',
        timestamp: new Date().toISOString(),
        services: serviceHealth,
        version: '1.0.0'
      });
    });

    // Service discovery endpoint
    this.app.get('/gateway/services', (req, res) => {
      const serviceList = {};
      for (const [name, service] of this.services.entries()) {
        serviceList[name] = {
          instances: service.instances.length,
          healthy: this.healthChecks.get(name)?.healthy || false,
          loadBalanceStrategy: service.loadBalanceStrategy
        };
      }
      res.json(serviceList);
    });

    // Dynamic proxy setup
    this.setupDynamicProxies();
  }

  /**
   * Setup dynamic proxies for registered services
   */
  setupDynamicProxies() {
    // License service proxy
    this.app.use('/api/license/*', this.createServiceProxy('license-service'));
    
    // Analytics service proxy
    this.app.use('/api/analytics/*', this.createServiceProxy('analytics-service'));
    
    // Security service proxy
    this.app.use('/api/security/*', this.createServiceProxy('security-service'));
    
    // User service proxy
    this.app.use('/api/user/*', this.createServiceProxy('user-service'));
    
    // Payment service proxy
    this.app.use('/api/payment/*', this.createServiceProxy('payment-service'));
  }

  /**
   * Create service proxy middleware
   */
  createServiceProxy(serviceName) {
    return createProxyMiddleware({
      target: 'http://localhost:3000', // Fallback to main server
      changeOrigin: true,
      pathRewrite: (path, req) => {
        // Remove service prefix from path
        return path.replace(`/api/${serviceName.replace('-service', '')}`, '');
      },
      router: (req) => {
        // Dynamic routing based on service health and load balancing
        const service = this.services.get(serviceName);
        if (service && service.instances.length > 0) {
          const instance = this.loadBalancers.get(serviceName).getNext();
          return instance.url;
        }
        return 'http://localhost:3000'; // Fallback
      },
      onError: (err, req, res) => {
        console.error(`🚨 Proxy error for ${serviceName}:`, err.message);
        res.status(503).json({ 
          error: 'Service temporarily unavailable',
          service: serviceName
        });
      },
      onProxyReq: (proxyReq, req, res) => {
        // Add service metadata headers
        proxyReq.setHeader('X-Gateway-Service', serviceName);
        proxyReq.setHeader('X-Gateway-Timestamp', new Date().toISOString());
        proxyReq.setHeader('X-Request-ID', this.generateRequestId());
      }
    });
  }

  /**
   * Create load balancer for service
   */
  createLoadBalancer(service) {
    return {
      getNext: () => {
        if (service.instances.length === 0) {
          throw new Error(`No healthy instances for service: ${service.name}`);
        }
        
        switch (service.loadBalanceStrategy) {
          case 'round-robin':
            const instance = service.instances[service.currentIndex];
            service.currentIndex = (service.currentIndex + 1) % service.instances.length;
            return instance;
            
          case 'random':
            const randomIndex = Math.floor(Math.random() * service.instances.length);
            return service.instances[randomIndex];
            
          case 'least-connections':
            // For now, use round-robin (would need connection tracking)
            return this.getNext();
            
          default:
            return service.instances[0];
        }
      }
    };
  }

  /**
   * Start health checking for all services
   */
  startHealthChecking() {
    setInterval(() => {
      this.checkAllServicesHealth();
    }, 30000); // Check every 30 seconds
    
    // Initial health check
    setTimeout(() => this.checkAllServicesHealth(), 5000);
  }

  /**
   * Check health of all registered services
   */
  async checkAllServicesHealth() {
    for (const [name, service] of this.services.entries()) {
      try {
        const healthyInstances = [];
        
        for (const instance of service.instances) {
          const isHealthy = await this.checkInstanceHealth(instance, service.healthEndpoint);
          if (isHealthy) {
            healthyInstances.push(instance);
          }
        }
        
        // Update service instances to only include healthy ones
        service.instances = healthyInstances;
        
        const health = {
          healthy: healthyInstances.length > 0,
          totalInstances: service.instances.length,
          healthyInstances: healthyInstances.length,
          lastCheck: new Date().toISOString()
        };
        
        this.healthChecks.set(name, health);
        
        if (healthyInstances.length === 0) {
          console.warn(`⚠️ No healthy instances for service: ${name}`);
          this.emit('serviceUnhealthy', { name, service });
        }
        
      } catch (error) {
        console.error(`❌ Health check failed for service ${name}:`, error.message);
        this.healthChecks.set(name, {
          healthy: false,
          error: error.message,
          lastCheck: new Date().toISOString()
        });
      }
    }
  }

  /**
   * Check health of individual service instance
   */
  async checkInstanceHealth(instance, healthEndpoint) {
    try {
      const response = await fetch(`${instance.url}${healthEndpoint}`, {
        method: 'GET',
        timeout: 5000
      });
      
      return response.ok;
    } catch (error) {
      return false;
    }
  }

  /**
   * Generate unique request ID
   */
  generateRequestId() {
    return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  /**
   * Get gateway statistics
   */
  getStatistics() {
    const stats = {
      totalServices: this.services.size,
      healthyServices: 0,
      totalInstances: 0,
      healthyInstances: 0,
      requestsPerMinute: 0, // Would need request tracking
      averageResponseTime: 0 // Would need response time tracking
    };
    
    for (const [name, health] of this.healthChecks.entries()) {
      if (health.healthy) {
        stats.healthyServices++;
      }
      stats.totalInstances += health.totalInstances || 0;
      stats.healthyInstances += health.healthyInstances || 0;
    }
    
    return stats;
  }

  /**
   * Start the gateway server
   */
  start(port = 8080) {
    this.server = this.app.listen(port, () => {
      console.log(`🌐 API Gateway running on port ${port}`);
      this.emit('gatewayStarted', { port });
    });
    
    return this.server;
  }

  /**
   * Stop the gateway server
   */
  stop() {
    if (this.server) {
      this.server.close();
      console.log('🌐 API Gateway stopped');
      this.emit('gatewayStopped');
    }
  }
}
