import * as plugins from '../../plugins.js';
import type { OpsServer } from '../classes.opsserver.js';
import * as interfaces from '../../../ts_interfaces/index.js';
import { MetricsManager } from '../../monitoring/index.js';

export class SecurityHandler {
  constructor(private opsServerRef: OpsServer) {
    this.registerHandlers();
  }

  private registerHandlers(): void {
    // All security endpoints register directly on viewRouter (valid identity required via middleware)
    const router = this.opsServerRef.viewRouter;

    // Security Metrics Handler
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetSecurityMetrics>(
        'getSecurityMetrics',
        async (dataArg, toolsArg) => {
          const metrics = await this.collectSecurityMetrics();
          return {
            metrics: {
              blockedIPs: metrics.blockedIPs,
              reputationScores: metrics.reputationScores,
              spamDetected: metrics.spamDetection.detected,
              malwareDetected: metrics.malwareDetected,
              phishingDetected: metrics.phishingDetected,
              authenticationFailures: metrics.authFailures,
              suspiciousActivities: metrics.suspiciousActivities,
            },
            trends: dataArg.includeDetails ? {
              spam: metrics.trends.spam,
              malware: metrics.trends.malware,
              phishing: metrics.trends.phishing,
            } : undefined,
          };
        }
      )
    );
    
    // Active Connections Handler
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetActiveConnections>(
        'getActiveConnections',
        async (dataArg, toolsArg) => {
          const connections = await this.getActiveConnections(dataArg.protocol, dataArg.state);
          const connectionInfos: interfaces.data.IConnectionInfo[] = connections.map(conn => ({
            id: conn.id,
            remoteAddress: conn.source.ip,
            localAddress: conn.destination.ip,
            startTime: conn.startTime,
            protocol: conn.type === 'http' ? 'https' : conn.type as any,
            state: conn.status as any,
            bytesReceived: Math.floor(conn.bytesTransferred / 2),
            bytesSent: Math.floor(conn.bytesTransferred / 2),
          }));
          
          const summary = {
            total: connectionInfos.length,
            byProtocol: connectionInfos.reduce((acc, conn) => {
              acc[conn.protocol] = (acc[conn.protocol] || 0) + 1;
              return acc;
            }, {} as { [protocol: string]: number }),
            byState: connectionInfos.reduce((acc, conn) => {
              acc[conn.state] = (acc[conn.state] || 0) + 1;
              return acc;
            }, {} as { [state: string]: number }),
          };
          
          return {
            connections: connectionInfos,
            summary,
          };
        }
      )
    );
    
    // Network Stats Handler - provides comprehensive network metrics
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetNetworkStats>(
        'getNetworkStats',
        async (dataArg, toolsArg) => {
          // Get network stats from MetricsManager if available
          if (this.opsServerRef.dcRouterRef.metricsManager) {
            const networkStats = await this.opsServerRef.dcRouterRef.metricsManager.getNetworkStats();

            // Convert per-IP throughput Map to serializable array
            const throughputByIP: Array<{ ip: string; in: number; out: number }> = [];
            if (networkStats.throughputByIP) {
              for (const [ip, tp] of networkStats.throughputByIP) {
                throughputByIP.push({ ip, in: tp.in, out: tp.out });
              }
            }

            return {
              connectionsByIP: Array.from(networkStats.connectionsByIP.entries()).map(([ip, count]) => ({ ip, count })),
              throughputRate: networkStats.throughputRate,
              topIPs: networkStats.topIPs,
              totalDataTransferred: networkStats.totalDataTransferred,
              throughputHistory: networkStats.throughputHistory || [],
              throughputByIP,
              requestsPerSecond: networkStats.requestsPerSecond || 0,
              requestsTotal: networkStats.requestsTotal || 0,
              backends: networkStats.backends || [],
            };
          }

          // Fallback if MetricsManager not available
          return {
            connectionsByIP: [],
            throughputRate: { bytesInPerSecond: 0, bytesOutPerSecond: 0 },
            topIPs: [],
            totalDataTransferred: { bytesIn: 0, bytesOut: 0 },
            throughputHistory: [],
            throughputByIP: [],
            requestsPerSecond: 0,
            requestsTotal: 0,
            backends: [],
          };
        }
      )
    );
    
    // Rate Limit Status Handler
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetRateLimitStatus>(
        'getRateLimitStatus',
        async (dataArg, toolsArg) => {
          const status = await this.getRateLimitStatus(dataArg.domain, dataArg.ip);
          const limits: interfaces.data.IRateLimitInfo[] = status.limits.map(limit => ({
            domain: limit.identifier,
            currentRate: limit.current,
            limit: limit.limit,
            remaining: limit.limit - limit.current,
            resetTime: limit.resetAt,
            blocked: limit.status === 'limited',
          }));
          
          return {
            limits,
            globalLimit: dataArg.includeBlocked ? {
              current: limits.reduce((sum, l) => sum + l.currentRate, 0),
              limit: 1000, // Global limit
              remaining: 1000 - limits.reduce((sum, l) => sum + l.currentRate, 0),
            } : undefined,
          };
        }
      )
    );
  }
  
  private async collectSecurityMetrics(): Promise<{
    blockedIPs: string[];
    reputationScores: { [domain: string]: number };
    spamDetection: {
      detected: number;
      falsePositives: number;
    };
    malwareDetected: number;
    phishingDetected: number;
    authFailures: number;
    suspiciousActivities: number;
    trends: {
      spam: Array<{ timestamp: number; value: number }>;
      malware: Array<{ timestamp: number; value: number }>;
      phishing: Array<{ timestamp: number; value: number }>;
    };
  }> {
    // Get metrics from MetricsManager if available
    if (this.opsServerRef.dcRouterRef.metricsManager) {
      const securityStats = await this.opsServerRef.dcRouterRef.metricsManager.getSecurityStats();
      return {
        blockedIPs: [], // TODO: Track actual blocked IPs
        reputationScores: {},
        spamDetection: {
          detected: securityStats.spamDetected,
          falsePositives: 0,
        },
        malwareDetected: securityStats.malwareDetected,
        phishingDetected: securityStats.phishingDetected,
        authFailures: securityStats.authFailures,
        suspiciousActivities: 0,
        trends: {
          spam: [],
          malware: [],
          phishing: [],
        },
      };
    }
    
    // Fallback if MetricsManager not available
    return {
      blockedIPs: [],
      reputationScores: {},
      spamDetection: {
        detected: 0,
        falsePositives: 0,
      },
      malwareDetected: 0,
      phishingDetected: 0,
      authFailures: 0,
      suspiciousActivities: 0,
      trends: {
        spam: [],
        malware: [],
        phishing: [],
      },
    };
  }
  
  private async getActiveConnections(
    protocol?: 'http' | 'https' | 'smtp' | 'smtps',
    state?: string
  ): Promise<Array<{
    id: string;
    type: 'http' | 'smtp' | 'dns';
    source: {
      ip: string;
      port: number;
      country?: string;
    };
    destination: {
      ip: string;
      port: number;
      service?: string;
    };
    startTime: number;
    bytesTransferred: number;
    status: 'active' | 'idle' | 'closing';
  }>> {
    const connections: Array<{
      id: string;
      type: 'http' | 'smtp' | 'dns';
      source: {
        ip: string;
        port: number;
        country?: string;
      };
      destination: {
        ip: string;
        port: number;
        service?: string;
      };
      startTime: number;
      bytesTransferred: number;
      status: 'active' | 'idle' | 'closing';
    }> = [];
    
    // Get connection info and network stats from MetricsManager if available
    if (this.opsServerRef.dcRouterRef.metricsManager) {
      const connectionInfo = await this.opsServerRef.dcRouterRef.metricsManager.getConnectionInfo();
      const networkStats = await this.opsServerRef.dcRouterRef.metricsManager.getNetworkStats();
      
      // Use IP-based connection data from the new metrics API
      if (networkStats.connectionsByIP && networkStats.connectionsByIP.size > 0) {
        let connIndex = 0;
        const publicIp = this.opsServerRef.dcRouterRef.options.publicIp || 'server';
        
        for (const [ip, count] of networkStats.connectionsByIP) {
          // Create a connection entry for each active IP connection
          for (let i = 0; i < Math.min(count, 5); i++) { // Limit to 5 connections per IP for UI performance
            connections.push({
              id: `conn-${connIndex++}`,
              type: 'http',
              source: {
                ip: ip,
                port: Math.floor(Math.random() * 50000) + 10000, // High port range
              },
              destination: {
                ip: publicIp,
                port: 443,
                service: 'proxy',
              },
              startTime: Date.now() - Math.floor(Math.random() * 3600000), // Within last hour
              bytesTransferred: Math.floor(networkStats.totalDataTransferred.bytesIn / networkStats.connectionsByIP.size),
              status: 'active',
            });
          }
        }
      } else if (connectionInfo.length > 0) {
        // Fallback to route-based connection info if no IP data available
        connectionInfo.forEach((info, index) => {
          connections.push({
            id: `conn-${index}`,
            type: 'http',
            source: {
              ip: 'unknown',
              port: 0,
            },
            destination: {
              ip: this.opsServerRef.dcRouterRef.options.publicIp || 'server',
              port: 443,
              service: info.source,
            },
            startTime: info.lastActivity.getTime(),
            bytesTransferred: 0,
            status: 'active',
          });
        });
      }
    }
    
    // Filter by protocol if specified
    if (protocol) {
      return connections.filter(conn => {
        if (protocol === 'https' || protocol === 'http') {
          return conn.type === 'http';
        }
        return conn.type === protocol.replace('s', ''); // smtp/smtps -> smtp
      });
    }
    
    return connections;
  }
  
  private async getRateLimitStatus(
    domain?: string,
    ip?: string
  ): Promise<{
    limits: Array<{
      identifier: string;
      type: 'ip' | 'domain' | 'email';
      limit: number;
      current: number;
      resetAt: number;
      status: 'ok' | 'warning' | 'limited';
    }>;
  }> {
    // TODO: Implement actual rate limit status collection
    return {
      limits: [],
    };
  }
}