/**
 * Environment Variable Validation Utility
 * 
 * Validates required environment variables on application startup.
 * Provides clear error messages if configuration is missing or invalid.
 */

const logger = require('./logger');

/**
 * Validates that required environment variables are set
 * @param {Object} config - Configuration object with variable definitions
 * @returns {Object} Validated environment variables
 * @throws {Error} If required variables are missing or invalid
 */
function validateEnv(config = {}) {
  const errors = [];
  const warnings = [];
  const validated = {};

  // Define required environment variables with validation rules
  const requiredVars = {
    JWT_SECRET: {
      required: true,
      minLength: 32,
      description: 'JWT secret for token signing',
      validate: (value) => {
        if (value === 'change-this-jwt-secret-key') {
          return 'JWT_SECRET is using the default example value. Please set a secure random string.';
        }
        if (value.length < 32) {
          return `JWT_SECRET must be at least 32 characters (currently ${value.length})`;
        }
        return null;
      }
    },
    COUCHDB_URL: {
      required: true,
      description: 'CouchDB connection URL',
      validate: (value) => {
        if (!value.startsWith('http://') && !value.startsWith('https://')) {
          return 'COUCHDB_URL must start with http:// or https://';
        }
        return null;
      }
    },
    COUCHDB_DB_NAME: {
      required: true,
      description: 'CouchDB database name',
      validate: (value) => {
        if (!/^[a-z][a-z0-9_$()+/-]*$/.test(value)) {
          return 'COUCHDB_DB_NAME must start with a lowercase letter and contain only lowercase letters, digits, and _, $, (, ), +, -, /';
        }
        return null;
      }
    },
    NODE_ENV: {
      required: false,
      default: 'development',
      description: 'Node environment',
      validate: (value) => {
        const valid = ['development', 'production', 'test'];
        if (!valid.includes(value)) {
          return `NODE_ENV must be one of: ${valid.join(', ')}`;
        }
        return null;
      }
    },
    PORT: {
      required: false,
      default: '5000',
      description: 'Server port',
      validate: (value) => {
        const port = parseInt(value, 10);
        if (isNaN(port) || port < 1 || port > 65535) {
          return 'PORT must be a valid port number (1-65535)';
        }
        return null;
      }
    },
    FRONTEND_URL: {
      required: false,
      default: 'http://localhost:3000',
      description: 'Frontend application URL for CORS',
      validate: (value) => {
        if (!value.startsWith('http://') && !value.startsWith('https://')) {
          return 'FRONTEND_URL must start with http:// or https://';
        }
        return null;
      }
    }
  };

  // Optional environment variables (warn if missing in production)
  const optionalVars = {
    COUCHDB_USER: 'CouchDB admin username',
    COUCHDB_PASSWORD: 'CouchDB admin password',
    CLOUDINARY_CLOUD_NAME: 'Cloudinary cloud name for image uploads',
    CLOUDINARY_API_KEY: 'Cloudinary API key',
    CLOUDINARY_API_SECRET: 'Cloudinary API secret',
    STRIPE_SECRET_KEY: 'Stripe secret key for payments',
    STRIPE_PUBLISHABLE_KEY: 'Stripe publishable key',
    OPENAI_API_KEY: 'OpenAI API key for AI features'
  };

  // Validate required variables
  for (const [varName, rules] of Object.entries(requiredVars)) {
    const value = process.env[varName];

    if (!value || value.trim() === '') {
      if (rules.required) {
        errors.push(`${varName} is required but not set. ${rules.description}`);
      } else if (rules.default) {
        validated[varName] = rules.default;
        logger.debug(`Using default value for ${varName}: ${rules.default}`);
      }
    } else {
      // Run custom validation if provided
      if (rules.validate) {
        const validationError = rules.validate(value);
        if (validationError) {
          errors.push(`${varName}: ${validationError}`);
        }
      }
      validated[varName] = value;
    }
  }

  // Check optional variables in production
  if (process.env.NODE_ENV === 'production') {
    for (const [varName, description] of Object.entries(optionalVars)) {
      const value = process.env[varName];
      if (!value || value.trim() === '') {
        warnings.push(`${varName} is not set. ${description} may not work.`);
      }
    }
  }

  // Log warnings
  if (warnings.length > 0) {
    logger.warn('Environment configuration warnings:');
    warnings.forEach(warning => logger.warn(`  - ${warning}`));
  }

  // Throw error if required variables are missing
  if (errors.length > 0) {
    const errorMessage = [
      'Environment validation failed. Missing or invalid required variables:',
      ...errors.map(err => `  - ${err}`),
      '',
      'Please check your .env file or environment configuration.',
      'See .env.example for required variables.'
    ].join('\n');
    
    throw new Error(errorMessage);
  }

  return validated;
}

/**
 * Logs current environment configuration (masks sensitive values)
 */
function logEnvConfig() {
  const sensitiveKeys = ['JWT_SECRET', 'COUCHDB_PASSWORD', 'COUCHDB_SECRET', 
                        'CLOUDINARY_API_SECRET', 'STRIPE_SECRET_KEY', 'OPENAI_API_KEY'];
  
  const config = {
    NODE_ENV: process.env.NODE_ENV || 'development',
    PORT: process.env.PORT || '5000',
    COUCHDB_URL: process.env.COUCHDB_URL || 'not set',
    COUCHDB_DB_NAME: process.env.COUCHDB_DB_NAME || 'not set',
    FRONTEND_URL: process.env.FRONTEND_URL || 'http://localhost:3000',
    COUCHDB_USER: process.env.COUCHDB_USER ? '***' : 'not set',
    JWT_SECRET: process.env.JWT_SECRET ? '***' : 'not set',
    CLOUDINARY_CONFIGURED: process.env.CLOUDINARY_CLOUD_NAME ? 'yes' : 'no',
    STRIPE_CONFIGURED: process.env.STRIPE_SECRET_KEY ? 'yes' : 'no',
    OPENAI_CONFIGURED: process.env.OPENAI_API_KEY ? 'yes' : 'no'
  };

  logger.info('Environment Configuration:');
  Object.entries(config).forEach(([key, value]) => {
    logger.info(`  ${key}: ${value}`);
  });
}

module.exports = {
  validateEnv,
  logEnvConfig
};
