// Environment Variable Validation
// Validates all required environment variables at application startup

import { logger } from '@/infrastructure/monitoring/logger';

interface EnvVarConfig {
  required: boolean;
  description: string;
  validator?: (value: string) => boolean;
  errorMessage?: string;
}

interface EnvConfig {
  [key: string]: EnvVarConfig;
}

// Environment variable definitions
const envConfig: EnvConfig = {
  // Database
  DATABASE_URL: {
    required: true,
    description: 'PostgreSQL database connection string',
    validator: (value) => value.startsWith('postgresql://') || value.startsWith('postgres://'),
    errorMessage: 'DATABASE_URL must be a valid PostgreSQL connection string',
  },

  // Security
  JWT_SECRET: {
    required: true,
    description: 'JWT secret key for token signing',
    validator: (value) => value.length >= 32,
    errorMessage: 'JWT_SECRET must be at least 32 characters long',
  },

  // API Configuration
  PORT: {
    required: false,
    description: 'Server port (default: 3000)',
    validator: (value) => {
      const port = parseInt(value, 10);
      return !isNaN(port) && port > 0 && port < 65536;
    },
    errorMessage: 'PORT must be a valid port number (1-65535)',
  },

  ALLOWED_ORIGINS: {
    required: process.env.NODE_ENV === 'production',
    description: 'Comma-separated list of allowed CORS origins',
    validator: (value) => {
      if (process.env.NODE_ENV === 'production' && value === '*') {
        return false;
      }
      return value.split(',').every((origin) => {
        try {
          new URL(origin.trim());
          return true;
        } catch {
          return false;
        }
      });
    },
    errorMessage:
      'ALLOWED_ORIGINS must be comma-separated valid URLs. Wildcard (*) not allowed in production.',
  },

  // HSM Configuration
  HSM_ENABLED: {
    required: false,
    description: 'Enable HSM integration (default: false)',
    validator: (value) => value === 'true' || value === 'false',
    errorMessage: 'HSM_ENABLED must be "true" or "false"',
  },

  // Logging
  LOG_LEVEL: {
    required: false,
    description: 'Logging level (default: info)',
    validator: (value) => ['error', 'warn', 'info', 'debug'].includes(value),
    errorMessage: 'LOG_LEVEL must be one of: error, warn, info, debug',
  },

  // Node Environment
  NODE_ENV: {
    required: false,
    description: 'Node environment (development, staging, production)',
    validator: (value) => ['development', 'staging', 'production', 'test'].includes(value),
    errorMessage: 'NODE_ENV must be one of: development, staging, production, test',
  },
};

/**
 * Validate environment variables
 * @throws Error if validation fails
 */
export function validateEnvironment(): void {
  const errors: string[] = [];
  const warnings: string[] = [];

  for (const [key, config] of Object.entries(envConfig)) {
    const value = process.env[key];

    // Check if required
    if (config.required && !value) {
      errors.push(
        `Missing required environment variable: ${key}\n  Description: ${config.description}`
      );
      continue;
    }

    // Skip validation if not set and not required
    if (!value) {
      continue;
    }

    // Run validator if provided
    if (config.validator && !config.validator(value)) {
      const errorMsg = config.errorMessage || `Invalid value for ${key}`;
      if (config.required) {
        errors.push(`Invalid environment variable ${key}: ${errorMsg}\n  Value: ${value}`);
      } else {
        warnings.push(`Invalid environment variable ${key}: ${errorMsg}\n  Value: ${value}`);
      }
    }
  }

  // Log warnings
  if (warnings.length > 0) {
    warnings.forEach((warning) => logger.warn(warning));
  }

  // Throw if there are errors
  if (errors.length > 0) {
    const errorMessage = `Environment validation failed:\n${errors.join('\n\n')}`;
    logger.error(errorMessage);
    throw new Error(errorMessage);
  }

  logger.info('Environment variables validated successfully');
}

/**
 * Get validated environment variable
 */
export function getEnv(key: string, defaultValue?: string): string {
  const value = process.env[key];
  if (!value && defaultValue === undefined) {
    throw new Error(`Environment variable ${key} is not set and no default provided`);
  }
  return value || defaultValue || '';
}

