/**
 * @fileoverview Tests for the monitoring generator
 */

import { beforeEach, describe, expect, it } from 'vitest';
import type { DeploymentConfig } from './adapter-interface.js';
import { MonitoringGenerator } from './monitoring-generator.js';

describe('MonitoringGenerator', () => {
  let monitoringGenerator: MonitoringGenerator;
  let mockDeploymentConfig: DeploymentConfig;

  beforeEach(() => {
    monitoringGenerator = new MonitoringGenerator();
    mockDeploymentConfig = {
      outputDir: 'dist',
      isStatic: false,
      includeServerFunctions: true,
      env: {
        NODE_ENV: 'production',
        PORT: '3000'
      }
    };
  });

  describe('generateMonitoringConfig', () => {
    it('should generate complete monitoring configuration', () => {
      const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig);

      expect(config).toHaveProperty('logger');
      expect(config).toHaveProperty('metrics');
      expect(config).toHaveProperty('tracing');
      expect(config).toHaveProperty('healthCheck');
      expect(config).toHaveProperty('errorHandler');
      expect(config).toHaveProperty('dockerCompose');
      expect(config).toHaveProperty('kubernetes');
    });

    it('should generate structured logging configuration', () => {
      const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
        structuredLogging: true,
        logLevel: 'info'
      });

      expect(config.logger).toContain('winston.createLogger');
      expect(config.logger).toContain('level: \'info\'');
      expect(config.logger).toContain('format.timestamp()');
      expect(config.logger).toContain('format.json()');
      expect(config.logger).toContain('winston.transports.Console');
      expect(config.logger).toContain('winston.transports.File');
      expect(config.logger).toContain('requestLogger');
    });

    it('should generate metrics collection configuration', () => {
      const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
        metricsCollection: true
      });

      expect(config.metrics).toContain('prom-client');
      expect(config.metrics).toContain('collectDefaultMetrics');
      expect(config.metrics).toContain('httpRequestDuration');
      expect(config.metrics).toContain('httpRequestTotal');
      expect(config.metrics).toContain('activeConnections');
      expect(config.metrics).toContain('memoryUsage');
      expect(config.metrics).toContain('metricsMiddleware');
      expect(config.metrics).toContain('metricsEndpoint');
    });

    it('should generate distributed tracing configuration', () => {
      const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
        distributedTracing: true
      });

      expect(config.tracing).toContain('@opentelemetry/api');
      expect(config.tracing).toContain('@opentelemetry/sdk-trace-node');
      expect(config.tracing).toContain('@opentelemetry/exporter-jaeger');
      expect(config.tracing).toContain('NodeTracerProvider');
      expect(config.tracing).toContain('JaegerExporter');
      expect(config.tracing).toContain('tracingMiddleware');
      expect(config.tracing).toContain('createSpan');
    });

    it('should generate health check configuration', () => {
      const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
        healthChecks: true
      });

      expect(config.healthCheck).toContain('createHealthCheck');
      expect(config.healthCheck).toContain('healthChecks');
      expect(config.healthCheck).toContain('database:');
      expect(config.healthCheck).toContain('redis:');
      expect(config.healthCheck).toContain('external:');
      expect(config.healthCheck).toContain('healthCheckMiddleware');
      expect(config.healthCheck).toContain('healthCheckEndpoint');
    });

    it('should generate error handler configuration', () => {
      const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
        errorReporting: true
      });

      expect(config.errorHandler).toContain('errorHandler');
      expect(config.errorHandler).toContain('asyncHandler');
      expect(config.errorHandler).toContain('unhandledRejection');
      expect(config.errorHandler).toContain('uncaughtException');
      expect(config.errorHandler).toContain('logger.error');
      expect(config.errorHandler).toContain('span.setStatus');
    });

    it('should generate Docker Compose monitoring services', () => {
      const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
        integrations: {
          prometheus: true,
          grafana: true,
          jaeger: true
        }
      });

      expect(config.dockerCompose).toContain('version: \'3.8\'');
      expect(config.dockerCompose).toContain('prometheus:');
      expect(config.dockerCompose).toContain('grafana:');
      expect(config.dockerCompose).toContain('jaeger:');
      expect(config.dockerCompose).toContain('redis:');
      expect(config.dockerCompose).toContain('image: prom/prometheus:latest');
      expect(config.dockerCompose).toContain('image: grafana/grafana:latest');
      expect(config.dockerCompose).toContain('image: jaegertracing/all-in-one:latest');
      expect(config.dockerCompose).toContain('image: redis:alpine');
    });

    it('should generate Kubernetes monitoring manifests', () => {
      const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
        integrations: {
          prometheus: true,
          grafana: true,
          jaeger: true
        }
      });

      expect(config.kubernetes).toContain('apiVersion: v1');
      expect(config.kubernetes).toContain('kind: ConfigMap');
      expect(config.kubernetes).toContain('name: prometheus-config');
      expect(config.kubernetes).toContain('kind: Deployment');
      expect(config.kubernetes).toContain('name: prometheus');
      expect(config.kubernetes).toContain('name: grafana');
      expect(config.kubernetes).toContain('name: jaeger');
      expect(config.kubernetes).toContain('kind: Service');
      expect(config.kubernetes).toContain('kind: PersistentVolumeClaim');
    });
  });

  describe('generateLoggerConfig', () => {
    it('should generate Winston logger configuration', () => {
      const config = {
        structuredLogging: true,
        logLevel: 'info',
        metricsCollection: true,
        distributedTracing: true,
        errorReporting: true,
        healthChecks: true,
        performanceMonitoring: true,
        alerting: true,
        integrations: {
          datadog: false,
          newrelic: false,
          sentry: false,
          prometheus: true,
          grafana: true
        }
      };

      const loggerConfig = monitoringGenerator.generateLoggerConfig(config);

      expect(loggerConfig).toContain('import winston from \'winston\'');
      expect(loggerConfig).toContain('winston.createLogger');
      expect(loggerConfig).toContain('level: \'info\'');
      expect(loggerConfig).toContain('format.timestamp()');
      expect(loggerConfig).toContain('format.errors({ stack: true })');
      expect(loggerConfig).toContain('format.json()');
      expect(loggerConfig).toContain('winston.transports.Console');
      expect(loggerConfig).toContain('winston.transports.File');
      expect(loggerConfig).toContain('requestLogger');
      expect(loggerConfig).toContain('export default logger');
    });

    it('should use custom log level', () => {
      const config = {
        ...monitoringGenerator['defaultConfig'],
        logLevel: 'debug'
      };

      const loggerConfig = monitoringGenerator.generateLoggerConfig(config);

      expect(loggerConfig).toContain('level: \'debug\'');
    });
  });

  describe('generateMetricsConfig', () => {
    it('should generate Prometheus metrics configuration', () => {
      const config = {
        structuredLogging: true,
        logLevel: 'info',
        metricsCollection: true,
        distributedTracing: true,
        errorReporting: true,
        healthChecks: true,
        performanceMonitoring: true,
        alerting: true,
        integrations: {
          datadog: false,
          newrelic: false,
          sentry: false,
          prometheus: true,
          grafana: true
        }
      };

      const metricsConfig = monitoringGenerator.generateMetricsConfig(config);

      expect(metricsConfig).toContain('import prometheus from \'prom-client\'');
      expect(metricsConfig).toContain('collectDefaultMetrics');
      expect(metricsConfig).toContain('httpRequestDuration');
      expect(metricsConfig).toContain('httpRequestTotal');
      expect(metricsConfig).toContain('activeConnections');
      expect(metricsConfig).toContain('memoryUsage');
      expect(metricsConfig).toContain('metricsMiddleware');
      expect(metricsConfig).toContain('metricsEndpoint');
      expect(metricsConfig).toContain('setInterval');
    });
  });

  describe('generateTracingConfig', () => {
    it('should generate OpenTelemetry tracing configuration', () => {
      const config = {
        structuredLogging: true,
        logLevel: 'info',
        metricsCollection: true,
        distributedTracing: true,
        errorReporting: true,
        healthChecks: true,
        performanceMonitoring: true,
        alerting: true,
        integrations: {
          datadog: false,
          newrelic: false,
          sentry: false,
          prometheus: true,
          grafana: true
        }
      };

      const tracingConfig = monitoringGenerator.generateTracingConfig(config);

      expect(tracingConfig).toContain('@opentelemetry/api');
      expect(tracingConfig).toContain('@opentelemetry/sdk-trace-node');
      expect(tracingConfig).toContain('@opentelemetry/exporter-jaeger');
      expect(tracingConfig).toContain('NodeTracerProvider');
      expect(tracingConfig).toContain('JaegerExporter');
      expect(tracingConfig).toContain('BatchSpanProcessor');
      expect(tracingConfig).toContain('registerInstrumentations');
      expect(tracingConfig).toContain('tracingMiddleware');
      expect(tracingConfig).toContain('createSpan');
      expect(tracingConfig).toContain('export { tracer }');
    });
  });

  describe('generateHealthCheckConfig', () => {
    it('should generate health check configuration', () => {
      const config = {
        structuredLogging: true,
        logLevel: 'info',
        metricsCollection: true,
        distributedTracing: true,
        errorReporting: true,
        healthChecks: true,
        performanceMonitoring: true,
        alerting: true,
        integrations: {
          datadog: false,
          newrelic: false,
          sentry: false,
          prometheus: true,
          grafana: true
        }
      };

      const healthCheckConfig = monitoringGenerator.generateHealthCheckConfig(config);

      expect(healthCheckConfig).toContain('createHealthCheck');
      expect(healthCheckConfig).toContain('healthChecks');
      expect(healthCheckConfig).toContain('database:');
      expect(healthCheckConfig).toContain('redis:');
      expect(healthCheckConfig).toContain('external:');
      expect(healthCheckConfig).toContain('healthCheckMiddleware');
      expect(healthCheckConfig).toContain('healthCheckEndpoint');
      expect(healthCheckConfig).toContain('status: \'healthy\'');
      expect(healthCheckConfig).toContain('status: \'unhealthy\'');
    });
  });

  describe('generateErrorHandlerConfig', () => {
    it('should generate error handler configuration', () => {
      const config = {
        structuredLogging: true,
        logLevel: 'info',
        metricsCollection: true,
        distributedTracing: true,
        errorReporting: true,
        healthChecks: true,
        performanceMonitoring: true,
        alerting: true,
        integrations: {
          datadog: false,
          newrelic: false,
          sentry: false,
          prometheus: true,
          grafana: true
        }
      };

      const errorHandlerConfig = monitoringGenerator.generateErrorHandlerConfig(config);

      expect(errorHandlerConfig).toContain('import logger from \'./logger.js\'');
      expect(errorHandlerConfig).toContain('import { tracer } from \'./tracing.js\'');
      expect(errorHandlerConfig).toContain('errorHandler');
      expect(errorHandlerConfig).toContain('asyncHandler');
      expect(errorHandlerConfig).toContain('unhandledRejection');
      expect(errorHandlerConfig).toContain('uncaughtException');
      expect(errorHandlerConfig).toContain('logger.error');
      expect(errorHandlerConfig).toContain('span.setStatus');
      expect(errorHandlerConfig).toContain('process.exit(1)');
    });
  });

  describe('generateDockerComposeMonitoring', () => {
    it('should generate Docker Compose monitoring services', () => {
      const config = {
        structuredLogging: true,
        logLevel: 'info',
        metricsCollection: true,
        distributedTracing: true,
        errorReporting: true,
        healthChecks: true,
        performanceMonitoring: true,
        alerting: true,
        integrations: {
          datadog: false,
          newrelic: false,
          sentry: false,
          prometheus: true,
          grafana: true
        }
      };

      const dockerCompose = monitoringGenerator.generateDockerComposeMonitoring(config);

      expect(dockerCompose).toContain('version: \'3.8\'');
      expect(dockerCompose).toContain('services:');
      expect(dockerCompose).toContain('prometheus:');
      expect(dockerCompose).toContain('grafana:');
      expect(dockerCompose).toContain('jaeger:');
      expect(dockerCompose).toContain('redis:');
      expect(dockerCompose).toContain('image: prom/prometheus:latest');
      expect(dockerCompose).toContain('image: grafana/grafana:latest');
      expect(dockerCompose).toContain('image: jaegertracing/all-in-one:latest');
      expect(dockerCompose).toContain('image: redis:alpine');
      expect(dockerCompose).toContain('volumes:');
      expect(dockerCompose).toContain('restart: unless-stopped');
    });
  });

  describe('generateKubernetesMonitoring', () => {
    it('should generate Kubernetes monitoring manifests', () => {
      const config = {
        structuredLogging: true,
        logLevel: 'info',
        metricsCollection: true,
        distributedTracing: true,
        errorReporting: true,
        healthChecks: true,
        performanceMonitoring: true,
        alerting: true,
        integrations: {
          datadog: false,
          newrelic: false,
          sentry: false,
          prometheus: true,
          grafana: true
        }
      };

      const kubernetes = monitoringGenerator.generateKubernetesMonitoring(config);

      expect(kubernetes).toContain('apiVersion: v1');
      expect(kubernetes).toContain('kind: ConfigMap');
      expect(kubernetes).toContain('name: prometheus-config');
      expect(kubernetes).toContain('kind: Deployment');
      expect(kubernetes).toContain('name: prometheus');
      expect(kubernetes).toContain('name: grafana');
      expect(kubernetes).toContain('name: jaeger');
      expect(kubernetes).toContain('kind: Service');
      expect(kubernetes).toContain('kind: PersistentVolumeClaim');
      expect(kubernetes).toContain('replicas: 1');
      expect(kubernetes).toContain('containerPort: 9090');
      expect(kubernetes).toContain('containerPort: 3000');
      expect(kubernetes).toContain('containerPort: 16686');
    });
  });

  describe('error handling', () => {
    it('should throw CLIError when monitoring config generation fails', () => {
      // Mock a scenario that would cause generation to fail
      const invalidConfig = {
        ...mockDeploymentConfig,
        outputDir: null as any
      };

      expect(() => {
        monitoringGenerator.generateMonitoringConfig(invalidConfig);
      }).toThrow();
    });
  });
});
