/**
 * HVAC Testing Framework - Secure Credential Management
 * 
 * Provides secure credential management with encryption, environment variable support,
 * and WordPress role-based authentication for the HVAC testing framework.
 * 
 * Security Features:
 * - AES-256-GCM encryption for credential storage
 * - Environment variable-based configuration
 * - Session integrity verification
 * - Automatic credential rotation support
 * - Secure memory handling
 * 
 * @author Claude Code - Emergency Security Response
 * @version 1.0.0
 * @security CRITICAL - Handles production authentication credentials
 */

const fs = require('fs').promises;
const path = require('path');
const crypto = require('crypto');
require('dotenv').config();

class SecureCredentialManager {
    constructor() {
        this.encryptionKey = this.getEncryptionKey();
        this.credentials = new Map();
        this.sessionData = new Map();
        this.auditLog = [];
        
        // Initialize audit logging
        this.auditLogger = this.createAuditLogger();
        
        // Validate environment configuration
        this.validateEnvironment();
    }

    /**
     * Get or generate encryption key for credential storage
     * @returns {Buffer} 256-bit encryption key
     */
    getEncryptionKey() {
        const keyHex = process.env.SESSION_ENCRYPTION_KEY;
        if (!keyHex) {
            throw new Error('SESSION_ENCRYPTION_KEY environment variable not set. Generate with: openssl rand -hex 32');
        }
        
        if (keyHex.length !== 64) { // 32 bytes = 64 hex characters
            throw new Error('SESSION_ENCRYPTION_KEY must be 64 hex characters (32 bytes)');
        }
        
        return Buffer.from(keyHex, 'hex');
    }

    /**
     * Validate required environment variables are present
     */
    validateEnvironment() {
        const required = [
            'STAGING_BASE_URL',
            'MASTER_TRAINER_USERNAME',
            'MASTER_TRAINER_PASSWORD',
            'REGULAR_TRAINER_USERNAME', 
            'REGULAR_TRAINER_PASSWORD',
            'SESSION_ENCRYPTION_KEY',
            'JWT_SECRET'
        ];

        const missing = required.filter(key => !process.env[key]);
        if (missing.length > 0) {
            throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
        }

        this.auditLog.push({
            timestamp: new Date().toISOString(),
            event: 'ENVIRONMENT_VALIDATED',
            details: 'All required environment variables present'
        });
    }

    /**
     * Get credentials for a specific user role
     * @param {string} role - User role (master_trainer, master_trainer_alt, regular_trainer, admin)
     * @returns {Object} Encrypted credential object
     */
    getCredentials(role) {
        const credentialMap = {
            master_trainer: {
                username: process.env.MASTER_TRAINER_USERNAME,
                password: process.env.MASTER_TRAINER_PASSWORD,
                email: process.env.MASTER_TRAINER_EMAIL,
                role: 'hvac_master_trainer'
            },
            master_trainer_alt: {
                username: process.env.MASTER_TRAINER_ALT_USERNAME,
                password: process.env.MASTER_TRAINER_ALT_PASSWORD,
                email: process.env.MASTER_TRAINER_ALT_EMAIL,
                role: 'hvac_master_trainer'
            },
            regular_trainer: {
                username: process.env.REGULAR_TRAINER_USERNAME,
                password: process.env.REGULAR_TRAINER_PASSWORD,
                email: process.env.REGULAR_TRAINER_EMAIL,
                role: 'hvac_trainer'
            },
            admin: {
                username: process.env.ADMIN_USERNAME,
                password: process.env.ADMIN_PASSWORD,
                email: process.env.ADMIN_EMAIL,
                role: 'administrator'
            }
        };

        const credentials = credentialMap[role];
        if (!credentials) {
            throw new Error(`Invalid role: ${role}`);
        }

        if (!credentials.username || !credentials.password) {
            throw new Error(`Incomplete credentials for role: ${role}`);
        }

        this.auditLog.push({
            timestamp: new Date().toISOString(),
            event: 'CREDENTIALS_ACCESSED',
            role: role,
            username: credentials.username
        });

        return this.encryptCredentials(credentials);
    }

    /**
     * Encrypt credentials using AES-256-GCM
     * @param {Object} credentials - Plain text credentials
     * @returns {Object} Encrypted credentials with metadata
     */
    encryptCredentials(credentials) {
        const iv = crypto.randomBytes(16);
        const cipher = crypto.createCipher('aes-256-gcm', this.encryptionKey, iv);
        
        const plaintext = JSON.stringify(credentials);
        let encrypted = cipher.update(plaintext, 'utf8', 'hex');
        encrypted += cipher.final('hex');
        
        const authTag = cipher.getAuthTag();
        
        return {
            encrypted,
            iv: iv.toString('hex'),
            authTag: authTag.toString('hex'),
            algorithm: 'aes-256-gcm',
            created: new Date().toISOString()
        };
    }

    /**
     * Decrypt credentials
     * @param {Object} encryptedData - Encrypted credential object
     * @returns {Object} Plain text credentials
     */
    decryptCredentials(encryptedData) {
        try {
            const decipher = crypto.createDecipher(
                'aes-256-gcm', 
                this.encryptionKey, 
                Buffer.from(encryptedData.iv, 'hex')
            );
            
            decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
            
            let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
            decrypted += decipher.final('utf8');
            
            return JSON.parse(decrypted);
        } catch (error) {
            this.auditLog.push({
                timestamp: new Date().toISOString(),
                event: 'DECRYPTION_FAILED',
                error: error.message
            });
            throw new Error('Failed to decrypt credentials');
        }
    }

    /**
     * Create authenticated session with integrity verification
     * @param {string} role - User role
     * @returns {Object} Session object with encrypted credentials and metadata
     */
    createSecureSession(role) {
        const sessionId = crypto.randomUUID();
        const credentials = this.getCredentials(role);
        
        const session = {
            sessionId,
            role,
            credentials,
            created: new Date().toISOString(),
            expires: new Date(Date.now() + (24 * 60 * 60 * 1000)).toISOString(), // 24 hours
            integrity: this.generateSessionIntegrityHash(sessionId, role, credentials)
        };

        this.sessionData.set(sessionId, session);

        this.auditLog.push({
            timestamp: new Date().toISOString(),
            event: 'SESSION_CREATED',
            sessionId,
            role,
            expires: session.expires
        });

        return session;
    }

    /**
     * Verify session integrity and return decrypted credentials
     * @param {string} sessionId - Session identifier
     * @returns {Object} Decrypted credentials if session is valid
     */
    getSessionCredentials(sessionId) {
        const session = this.sessionData.get(sessionId);
        if (!session) {
            throw new Error('Session not found');
        }

        // Check expiration
        if (new Date() > new Date(session.expires)) {
            this.sessionData.delete(sessionId);
            throw new Error('Session expired');
        }

        // Verify integrity
        const expectedHash = this.generateSessionIntegrityHash(
            sessionId, 
            session.role, 
            session.credentials
        );
        
        if (session.integrity !== expectedHash) {
            this.sessionData.delete(sessionId);
            this.auditLog.push({
                timestamp: new Date().toISOString(),
                event: 'SESSION_INTEGRITY_VIOLATION',
                sessionId
            });
            throw new Error('Session integrity violation detected');
        }

        return this.decryptCredentials(session.credentials);
    }

    /**
     * Generate session integrity hash
     * @param {string} sessionId 
     * @param {string} role 
     * @param {Object} encryptedCredentials 
     * @returns {string} HMAC-SHA256 hash
     */
    generateSessionIntegrityHash(sessionId, role, encryptedCredentials) {
        const data = JSON.stringify({ sessionId, role, encryptedCredentials });
        return crypto.createHmac('sha256', this.encryptionKey)
            .update(data)
            .digest('hex');
    }

    /**
     * Destroy session securely
     * @param {string} sessionId 
     */
    destroySession(sessionId) {
        if (this.sessionData.delete(sessionId)) {
            this.auditLog.push({
                timestamp: new Date().toISOString(),
                event: 'SESSION_DESTROYED',
                sessionId
            });
        }
    }

    /**
     * Get base URL with SSL/TLS validation
     * @returns {string} Validated base URL
     */
    getBaseUrl() {
        const baseUrl = process.env.STAGING_BASE_URL;
        if (!baseUrl) {
            throw new Error('STAGING_BASE_URL environment variable not set');
        }

        // Ensure HTTPS for production environments
        if (!baseUrl.startsWith('https://')) {
            throw new Error('Base URL must use HTTPS for security');
        }

        return baseUrl;
    }

    /**
     * Get TLS validation mode
     * @returns {string} Validation mode (strict|permissive)
     */
    getTLSValidationMode() {
        return process.env.TLS_VALIDATION_MODE || 'strict';
    }

    /**
     * Create audit logger for security events
     * @returns {Function} Audit logging function
     */
    createAuditLogger() {
        return async (event, details = {}) => {
            const auditEntry = {
                timestamp: new Date().toISOString(),
                event,
                ...details
            };

            this.auditLog.push(auditEntry);

            // Write to file if enabled
            if (process.env.ENABLE_SECURITY_AUDIT === 'true') {
                try {
                    const logFile = process.env.AUDIT_LOG_FILE || './security-audit.log';
                    await fs.appendFile(logFile, JSON.stringify(auditEntry) + '\n');
                } catch (error) {
                    console.warn('Failed to write security audit log:', error.message);
                }
            }
        };
    }

    /**
     * Export audit log for security review
     * @returns {Array} Complete audit log
     */
    getAuditLog() {
        return [...this.auditLog];
    }

    /**
     * Clear sensitive data from memory (call on shutdown)
     */
    secureCleanup() {
        this.credentials.clear();
        this.sessionData.clear();
        
        // Overwrite sensitive data
        if (this.encryptionKey) {
            this.encryptionKey.fill(0);
        }

        this.auditLogger('SECURE_CLEANUP_COMPLETED');
    }
}

// Singleton instance for global use
let credentialManagerInstance = null;

/**
 * Get singleton instance of SecureCredentialManager
 * @returns {SecureCredentialManager}
 */
function getCredentialManager() {
    if (!credentialManagerInstance) {
        credentialManagerInstance = new SecureCredentialManager();
    }
    return credentialManagerInstance;
}

module.exports = {
    SecureCredentialManager,
    getCredentialManager
};