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';
import { SecurityLogger } from '../../security/classes.securitylogger.js';
import { commitinfo } from '../../00_commitinfo_data.js';

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

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

    // Server Statistics Handler
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetServerStatistics>(
        'getServerStatistics',
        async (dataArg, toolsArg) => {
          const stats = await this.collectServerStats();
          return {
            stats: {
              uptime: stats.uptime,
              startTime: Date.now() - (stats.uptime * 1000),
              memoryUsage: stats.memoryUsage,
              cpuUsage: stats.cpuUsage,
              activeConnections: stats.activeConnections,
              totalConnections: stats.totalConnections,
              requestsPerSecond: stats.requestsPerSecond,
              throughput: stats.throughput,
            },
            history: dataArg.includeHistory ? stats.history : undefined,
          };
        }
      )
    );
    
    // Email Statistics Handler
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetEmailStatistics>(
        'getEmailStatistics',
        async (dataArg, toolsArg) => {
          const emailServer = this.opsServerRef.dcRouterRef.emailServer;
          if (!emailServer) {
            return {
              stats: {
                sent: 0,
                received: 0,
                bounced: 0,
                queued: 0,
                failed: 0,
                averageDeliveryTime: 0,
                deliveryRate: 0,
                bounceRate: 0,
              },
            };
          }
          
          const stats = await this.collectEmailStats();
          return {
            stats: {
              sent: stats.sentToday,
              received: stats.receivedToday,
              bounced: Math.floor(stats.sentToday * stats.bounceRate / 100),
              queued: stats.queueSize,
              failed: 0,
              averageDeliveryTime: 0,
              deliveryRate: stats.deliveryRate,
              bounceRate: stats.bounceRate,
            },
            domainBreakdown: dataArg.includeDetails ? stats.domainBreakdown : undefined,
          };
        }
      )
    );
    
    // DNS Statistics Handler
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetDnsStatistics>(
        'getDnsStatistics',
        async (dataArg, toolsArg) => {
          const dnsServer = this.opsServerRef.dcRouterRef.dnsServer;
          if (!dnsServer) {
            return {
              stats: {
                totalQueries: 0,
                cacheHits: 0,
                cacheMisses: 0,
                cacheHitRate: 0,
                activeDomains: 0,
                averageResponseTime: 0,
                queryTypes: {},
              },
            };
          }
          
          const stats = await this.collectDnsStats();
          return {
            stats: {
              totalQueries: stats.totalQueries,
              cacheHits: stats.cacheHits,
              cacheMisses: stats.cacheMisses,
              cacheHitRate: stats.cacheHitRate,
              activeDomains: stats.topDomains.length,
              averageResponseTime: 0,
              queryTypes: stats.queryTypes,
            },
            domainBreakdown: dataArg.includeQueryTypes ? stats.domainBreakdown : undefined,
          };
        }
      )
    );
    
    // Queue Status Handler
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetQueueStatus>(
        'getQueueStatus',
        async (dataArg, toolsArg) => {
          const emailServer = this.opsServerRef.dcRouterRef.emailServer;
          const queues: interfaces.data.IQueueStatus[] = [];
          
          if (emailServer) {
            const status = await this.getQueueStatus();
            queues.push({
              name: dataArg.queueName || 'default',
              size: status.pending,
              processing: status.active,
              failed: status.failed,
              retrying: status.retrying,
              averageProcessingTime: 0,
            });
          }
          
          return {
            queues,
            totalItems: queues.reduce((sum, q) => sum + q.size + q.processing + q.failed + q.retrying, 0),
          };
        }
      )
    );
    
    // Health Status Handler
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetHealthStatus>(
        'getHealthStatus',
        async (dataArg, toolsArg) => {
          const health = await this.checkHealthStatus();
          return {
            health: {
              healthy: health.healthy,
              uptime: process.uptime(),
              services: health.services.reduce((acc, service) => {
                acc[service.name] = {
                  status: service.status,
                  message: service.message,
                  lastCheck: Date.now(),
                };
                return acc;
              }, {} as any),
              version: commitinfo.version,
            },
          };
        }
      )
    );
    
    // Combined Metrics Handler - More efficient for frontend polling
    router.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetCombinedMetrics>(
        'getCombinedMetrics',
        async (dataArg, toolsArg) => {
          const sections = dataArg.sections || {
            server: true,
            email: true,
            dns: true,
            security: true,
            network: true,
          };
          
          const metrics: any = {};
          
          // Run all metrics collection in parallel
          const promises: Promise<void>[] = [];
          
          if (sections.server) {
            promises.push(
              this.collectServerStats().then(stats => {
                metrics.server = {
                  uptime: stats.uptime,
                  startTime: Date.now() - (stats.uptime * 1000),
                  memoryUsage: stats.memoryUsage,
                  cpuUsage: stats.cpuUsage,
                  activeConnections: stats.activeConnections,
                  totalConnections: stats.totalConnections,
                  requestsPerSecond: stats.requestsPerSecond,
                  throughput: stats.throughput,
                };
              })
            );
          }
          
          if (sections.email) {
            promises.push(
              this.collectEmailStats().then(stats => {
                // Get time-series data from MetricsManager
                const timeSeries = this.opsServerRef.dcRouterRef.metricsManager
                  ? this.opsServerRef.dcRouterRef.metricsManager.getEmailTimeSeries(24)
                  : undefined;

                metrics.email = {
                  sent: stats.sentToday,
                  received: stats.receivedToday,
                  bounced: Math.floor(stats.sentToday * stats.bounceRate / 100),
                  queued: stats.queueSize,
                  failed: 0,
                  averageDeliveryTime: 0,
                  deliveryRate: stats.deliveryRate,
                  bounceRate: stats.bounceRate,
                  timeSeries,
                };
              })
            );
          }
          
          if (sections.dns) {
            promises.push(
              this.collectDnsStats().then(stats => {
                // Get time-series data from MetricsManager
                const timeSeries = this.opsServerRef.dcRouterRef.metricsManager
                  ? this.opsServerRef.dcRouterRef.metricsManager.getDnsTimeSeries(24)
                  : undefined;

                metrics.dns = {
                  totalQueries: stats.totalQueries,
                  cacheHits: stats.cacheHits,
                  cacheMisses: stats.cacheMisses,
                  cacheHitRate: stats.cacheHitRate,
                  activeDomains: stats.topDomains.length,
                  averageResponseTime: 0,
                  queryTypes: stats.queryTypes,
                  timeSeries,
                  recentQueries: stats.recentQueries,
                };
              })
            );
          }
          
          if (sections.security && this.opsServerRef.dcRouterRef.metricsManager) {
            promises.push(
              this.opsServerRef.dcRouterRef.metricsManager.getSecurityStats().then(stats => {
                // Get recent events from the SecurityLogger singleton
                const securityLogger = SecurityLogger.getInstance();
                const recentEvents = securityLogger.getRecentEvents(50).map((evt) => ({
                  timestamp: evt.timestamp,
                  level: evt.level,
                  type: evt.type,
                  message: evt.message,
                  details: evt.details,
                  ipAddress: evt.ipAddress,
                  domain: evt.domain,
                  success: evt.success,
                }));

                metrics.security = {
                  blockedIPs: stats.blockedIPs,
                  reputationScores: {},
                  spamDetected: stats.spamDetected,
                  malwareDetected: stats.malwareDetected,
                  phishingDetected: stats.phishingDetected,
                  authenticationFailures: stats.authFailures,
                  suspiciousActivities: stats.totalThreatsBlocked,
                  recentEvents,
                };
              })
            );
          }
          
          if (sections.network && this.opsServerRef.dcRouterRef.metricsManager) {
            promises.push(
              (async () => {
                const stats = await this.opsServerRef.dcRouterRef.metricsManager!.getNetworkStats();
                const serverStats = await this.collectServerStats();

                // Build per-IP bandwidth lookup from throughputByIP
                const ipBandwidth = new Map<string, { in: number; out: number }>();
                if (stats.throughputByIP) {
                  for (const [ip, tp] of stats.throughputByIP) {
                    ipBandwidth.set(ip, { in: tp.in, out: tp.out });
                  }
                }

                metrics.network = {
                  totalBandwidth: {
                    in: stats.throughputRate.bytesInPerSecond,
                    out: stats.throughputRate.bytesOutPerSecond,
                  },
                  totalBytes: {
                    in: stats.totalDataTransferred.bytesIn,
                    out: stats.totalDataTransferred.bytesOut,
                  },
                  activeConnections: serverStats.activeConnections,
                  connectionDetails: [],
                  topEndpoints: stats.topIPs.map(ip => ({
                    endpoint: ip.ip,
                    requests: ip.count,
                    bandwidth: ipBandwidth.get(ip.ip) || { in: 0, out: 0 },
                  })),
                  throughputHistory: stats.throughputHistory || [],
                  requestsPerSecond: stats.requestsPerSecond || 0,
                  requestsTotal: stats.requestsTotal || 0,
                  backends: stats.backends || [],
                };
              })()
            );
          }

          if (sections.radius) {
            promises.push(
              (async () => {
                const radiusServer = this.opsServerRef.dcRouterRef.radiusServer;
                if (!radiusServer) return;
                const stats = radiusServer.getStats();
                const accountingStats = radiusServer.getAccountingManager().getStats();
                metrics.radius = {
                  running: stats.running,
                  uptime: stats.uptime,
                  authRequests: stats.authRequests,
                  authAccepts: stats.authAccepts,
                  authRejects: stats.authRejects,
                  accountingRequests: stats.accountingRequests,
                  activeSessions: stats.activeSessions,
                  totalInputBytes: accountingStats.totalInputBytes,
                  totalOutputBytes: accountingStats.totalOutputBytes,
                };
              })()
            );
          }

          if (sections.vpn) {
            promises.push(
              (async () => {
                const vpnManager = this.opsServerRef.dcRouterRef.vpnManager;
                const vpnConfig = this.opsServerRef.dcRouterRef.options.vpnConfig;
                if (!vpnManager) return;
                const connected = await vpnManager.getConnectedClients();
                metrics.vpn = {
                  running: vpnManager.running,
                  subnet: vpnManager.getSubnet(),
                  registeredClients: vpnManager.listClients().length,
                  connectedClients: connected.length,
                  wgListenPort: vpnConfig?.wgListenPort ?? 51820,
                };
              })()
            );
          }

          await Promise.all(promises);
          
          return {
            metrics,
            timestamp: Date.now(),
          };
        }
      )
    );
  }
  
  private async collectServerStats(): Promise<{
    uptime: number;
    cpuUsage: {
      user: number;
      system: number;
    };
    memoryUsage: interfaces.data.IServerStats['memoryUsage'];
    requestsPerSecond: number;
    activeConnections: number;
    totalConnections: number;
    throughput: interfaces.data.IServerStats['throughput'];
    history: Array<{
      timestamp: number;
      value: number;
    }>;
  }> {
    // Get metrics from MetricsManager if available
    if (this.opsServerRef.dcRouterRef.metricsManager) {
      const serverStats = await this.opsServerRef.dcRouterRef.metricsManager.getServerStats();
      return {
        uptime: serverStats.uptime,
        cpuUsage: serverStats.cpuUsage,
        memoryUsage: serverStats.memoryUsage,
        requestsPerSecond: serverStats.requestsPerSecond,
        activeConnections: serverStats.activeConnections,
        totalConnections: serverStats.totalConnections,
        throughput: serverStats.throughput,
        history: [], // TODO: Implement history tracking
      };
    }

    // Fallback to basic stats if MetricsManager not available
    const uptime = process.uptime();
    const memUsage = process.memoryUsage();
    const cpuUsage = plugins.os.loadavg()[0] * 100 / plugins.os.cpus().length;

    return {
      uptime,
      cpuUsage: {
        user: cpuUsage * 0.7,
        system: cpuUsage * 0.3,
      },
      memoryUsage: {
        heapUsed: memUsage.heapUsed,
        heapTotal: memUsage.heapTotal,
        external: memUsage.external,
        rss: memUsage.rss,
      },
      requestsPerSecond: 0,
      activeConnections: 0,
      totalConnections: 0,
      throughput: { bytesIn: 0, bytesOut: 0, bytesInPerSecond: 0, bytesOutPerSecond: 0 },
      history: [],
    };
  }
  
  private async collectEmailStats(): Promise<{
    sentToday: number;
    receivedToday: number;
    bounceRate: number;
    deliveryRate: number;
    queueSize: number;
    domainBreakdown?: { [domain: string]: interfaces.data.IEmailStats };
  }> {
    // Get metrics from MetricsManager if available
    if (this.opsServerRef.dcRouterRef.metricsManager) {
      const emailStats = await this.opsServerRef.dcRouterRef.metricsManager.getEmailStats();
      return {
        sentToday: emailStats.sentToday,
        receivedToday: emailStats.receivedToday,
        bounceRate: emailStats.bounceRate,
        deliveryRate: emailStats.deliveryRate,
        queueSize: emailStats.queueSize,
      };
    }
    
    // Fallback if MetricsManager not available
    return {
      sentToday: 0,
      receivedToday: 0,
      bounceRate: 0,
      deliveryRate: 100,
      queueSize: 0,
    };
  }
  
  private async collectDnsStats(): Promise<{
    queriesPerSecond: number;
    totalQueries: number;
    cacheHits: number;
    cacheMisses: number;
    cacheHitRate: number;
    topDomains: Array<{
      domain: string;
      count: number;
    }>;
    queryTypes: { [key: string]: number };
    recentQueries?: Array<{ timestamp: number; domain: string; type: string; answered: boolean; responseTimeMs: number }>;
    domainBreakdown?: { [domain: string]: interfaces.data.IDnsStats };
  }> {
    // Get metrics from MetricsManager if available
    if (this.opsServerRef.dcRouterRef.metricsManager) {
      const dnsStats = await this.opsServerRef.dcRouterRef.metricsManager.getDnsStats();
      return {
        queriesPerSecond: dnsStats.queriesPerSecond,
        totalQueries: dnsStats.totalQueries,
        cacheHits: dnsStats.cacheHits,
        cacheMisses: dnsStats.cacheMisses,
        cacheHitRate: dnsStats.cacheHitRate,
        topDomains: dnsStats.topDomains,
        queryTypes: dnsStats.queryTypes,
        recentQueries: dnsStats.recentQueries,
      };
    }

    // Fallback if MetricsManager not available
    return {
      queriesPerSecond: 0,
      totalQueries: 0,
      cacheHits: 0,
      cacheMisses: 0,
      cacheHitRate: 0,
      topDomains: [],
      queryTypes: {},
    };
  }
  
  private async getQueueStatus(): Promise<{
    pending: number;
    active: number;
    failed: number;
    retrying: number;
    items: Array<{
      id: string;
      recipient: string;
      subject: string;
      status: string;
      attempts: number;
      nextRetry?: number;
    }>;
  }> {
    // TODO: Implement actual queue status collection
    return {
      pending: 0,
      active: 0,
      failed: 0,
      retrying: 0,
      items: [],
    };
  }
  
  private async checkHealthStatus(): Promise<{
    healthy: boolean;
    services: Array<{
      name: string;
      status: 'healthy' | 'degraded' | 'unhealthy';
      message?: string;
    }>;
    checks: Array<{
      name: string;
      passed: boolean;
      message?: string;
    }>;
  }> {
    const dcRouter = this.opsServerRef.dcRouterRef;
    const health = dcRouter.serviceManager.getHealth();

    const services = health.services.map((svc) => {
      let status: 'healthy' | 'degraded' | 'unhealthy';
      switch (svc.state) {
        case 'running':
          status = 'healthy';
          break;
        case 'starting':
        case 'degraded':
          status = 'degraded';
          break;
        case 'failed':
          status = svc.criticality === 'critical' ? 'unhealthy' : 'degraded';
          break;
        case 'stopped':
        case 'stopping':
        default:
          status = 'degraded';
          break;
      }

      let message: string | undefined;
      if (svc.state === 'failed' && svc.lastError) {
        message = svc.lastError;
      } else if (svc.retryCount > 0 && svc.state !== 'running') {
        message = `Retry attempt ${svc.retryCount}`;
      }

      return { name: svc.name, status, message };
    });

    const healthy = health.overall === 'healthy';

    return {
      healthy,
      services,
      checks: [
        {
          name: 'Memory Usage',
          passed: process.memoryUsage().heapUsed < (plugins.os.totalmem() * 0.9),
          message: 'Memory usage within limits',
        },
      ],
    };
  }
}