/**
 * HVAC Testing Framework - Secure Input Validation
 * 
 * Provides comprehensive input validation and sanitization for all data entry points
 * to prevent injection attacks, XSS, and data corruption vulnerabilities.
 * 
 * Security Features:
 * - SQL injection prevention
 * - XSS prevention with content sanitization
 * - Command injection prevention
 * - WordPress-specific validation patterns
 * - File upload security validation
 * - URL and email validation with security checks
 * 
 * @author Claude Code - Emergency Security Response
 * @version 1.0.0
 * @security CRITICAL - Prevents injection and data validation vulnerabilities
 */

const crypto = require('crypto');
const validator = require('validator');
const { getCredentialManager } = require('./SecureCredentialManager');

class SecureInputValidator {
    constructor() {
        this.credentialManager = getCredentialManager();
        this.validationPatterns = this.initializeValidationPatterns();
        this.sanitizationRules = this.initializeSanitizationRules();
        this.validationLog = [];
    }

    /**
     * Initialize validation patterns for different data types
     * @returns {Map} Validation patterns
     */
    initializeValidationPatterns() {
        return new Map([
            // WordPress-specific patterns
            ['wp_username', /^[a-zA-Z0-9@._-]{1,60}$/],
            ['wp_email', /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/],
            ['wp_slug', /^[a-z0-9-]+$/],
            ['wp_role', /^(administrator|hvac_master_trainer|hvac_trainer|subscriber)$/],
            ['wp_nonce', /^[a-f0-9]{10}$/],
            ['wp_capability', /^[a-z_]+$/],
            
            // URL and path patterns
            ['safe_url', /^https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\/[a-zA-Z0-9._~:/?#[\]@!$&'()*+,;=-]*)?$/],
            ['relative_path', /^\/[a-zA-Z0-9._~:/?#[\]@!$&'()*+,;=-]*$/],
            ['file_path', /^[a-zA-Z0-9._/-]+$/],
            
            // Database and query patterns
            ['table_name', /^[a-zA-Z_][a-zA-Z0-9_]*$/],
            ['column_name', /^[a-zA-Z_][a-zA-Z0-9_]*$/],
            ['order_direction', /^(ASC|DESC)$/i],
            ['limit_value', /^\d+$/],
            
            // Form field patterns
            ['text_field', /^[a-zA-Z0-9\s.,!?-]{0,1000}$/],
            ['name_field', /^[a-zA-Z\s-]{1,100}$/],
            ['phone_field', /^[\+]?[1-9][\d]{0,15}$/],
            ['alphanumeric', /^[a-zA-Z0-9]+$/],
            ['numeric', /^\d+$/],
            
            // Security-specific patterns
            ['session_id', /^[a-f0-9-]{36}$/],
            ['csrf_token', /^[a-zA-Z0-9+/=]{32,}$/],
            ['api_key', /^[a-zA-Z0-9]{32,}$/],
            
            // File and upload patterns
            ['safe_filename', /^[a-zA-Z0-9._-]+\.(jpg|jpeg|png|gif|pdf|doc|docx|txt)$/i],
            ['image_filename', /^[a-zA-Z0-9._-]+\.(jpg|jpeg|png|gif)$/i],
            ['document_filename', /^[a-zA-Z0-9._-]+\.(pdf|doc|docx|txt)$/i]
        ]);
    }

    /**
     * Initialize sanitization rules for different contexts
     * @returns {Map} Sanitization rules
     */
    initializeSanitizationRules() {
        return new Map([
            // HTML sanitization
            ['html', {
                allowedTags: ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li'],
                stripScripts: true,
                stripStyles: true,
                stripComments: true
            }],
            
            // SQL sanitization
            ['sql', {
                escapeQuotes: true,
                stripComments: true,
                allowedChars: /^[a-zA-Z0-9\s.,_-]*$/
            }],
            
            // JavaScript sanitization
            ['js', {
                stripScripts: true,
                stripEvents: true,
                stripEval: true
            }],
            
            // WordPress content sanitization
            ['wp_content', {
                allowedTags: ['p', 'br', 'strong', 'em', 'a', 'ul', 'ol', 'li'],
                allowedAttributes: ['href', 'title'],
                stripScripts: true
            }]
        ]);
    }

    /**
     * Validate input against a specific pattern
     * @param {string} input - Input to validate
     * @param {string} patternName - Pattern name from validationPatterns
     * @param {Object} options - Validation options
     * @returns {Object} Validation result
     */
    validate(input, patternName, options = {}) {
        const validationId = this.generateValidationId();
        const startTime = Date.now();

        try {
            // Basic input checks
            if (input === null || input === undefined) {
                throw new Error('Input cannot be null or undefined');
            }

            // Convert to string for validation
            const inputStr = String(input).trim();

            // Length checks
            if (options.minLength && inputStr.length < options.minLength) {
                throw new Error(`Input too short (minimum ${options.minLength} characters)`);
            }

            if (options.maxLength && inputStr.length > options.maxLength) {
                throw new Error(`Input too long (maximum ${options.maxLength} characters)`);
            }

            // Pattern validation
            const pattern = this.validationPatterns.get(patternName);
            if (!pattern) {
                throw new Error(`Unknown validation pattern: ${patternName}`);
            }

            if (!pattern.test(inputStr)) {
                throw new Error(`Input does not match required pattern: ${patternName}`);
            }

            // Additional security checks
            this.performSecurityChecks(inputStr, patternName);

            // Log successful validation
            this.logValidation(validationId, patternName, 'SUCCESS', {
                inputLength: inputStr.length,
                duration: Date.now() - startTime
            });

            return {
                valid: true,
                sanitized: inputStr,
                pattern: patternName,
                validationId
            };

        } catch (error) {
            // Log failed validation
            this.logValidation(validationId, patternName, 'FAILED', {
                error: error.message,
                inputLength: input ? String(input).length : 0,
                duration: Date.now() - startTime
            });

            return {
                valid: false,
                error: error.message,
                pattern: patternName,
                validationId
            };
        }
    }

    /**
     * Sanitize input for a specific context
     * @param {string} input - Input to sanitize
     * @param {string} context - Sanitization context
     * @returns {string} Sanitized input
     */
    sanitize(input, context) {
        if (!input) return '';

        const rules = this.sanitizationRules.get(context);
        if (!rules) {
            throw new Error(`Unknown sanitization context: ${context}`);
        }

        let sanitized = String(input).trim();

        switch (context) {
            case 'html':
                sanitized = this.sanitizeHTML(sanitized, rules);
                break;
            case 'sql':
                sanitized = this.sanitizeSQL(sanitized, rules);
                break;
            case 'js':
                sanitized = this.sanitizeJavaScript(sanitized, rules);
                break;
            case 'wp_content':
                sanitized = this.sanitizeWordPressContent(sanitized, rules);
                break;
            default:
                sanitized = this.sanitizeGeneric(sanitized);
        }

        this.logSanitization(context, input.length, sanitized.length);
        return sanitized;
    }

    /**
     * Validate and sanitize input in one operation
     * @param {string} input - Input to process
     * @param {string} patternName - Validation pattern
     * @param {string} sanitizeContext - Sanitization context
     * @param {Object} options - Processing options
     * @returns {Object} Processing result
     */
    validateAndSanitize(input, patternName, sanitizeContext, options = {}) {
        // First sanitize to remove potential threats
        const sanitized = this.sanitize(input, sanitizeContext);
        
        // Then validate the sanitized input
        const validation = this.validate(sanitized, patternName, options);
        
        return {
            ...validation,
            originalInput: input,
            sanitizedInput: sanitized
        };
    }

    /**
     * Perform additional security checks on input
     * @param {string} input - Input to check
     * @param {string} patternName - Pattern being validated
     */
    performSecurityChecks(input, patternName) {
        // Check for common injection patterns
        const dangerousPatterns = [
            // SQL Injection
            /('|(\\')|(;|;$)|(\'|\"|\`)/,
            /(union|select|insert|update|delete|drop|create|alter|exec|execute)/i,
            
            // XSS patterns
            /<script[^>]*>.*?<\/script>/gi,
            /<iframe[^>]*>.*?<\/iframe>/gi,
            /javascript:/gi,
            /on\w+\s*=/gi,
            
            // Command injection
            /[;&|`$(){}]/,
            /(rm|del|format|shutdown|reboot)/i,
            
            // Path traversal
            /\.\.[\/\\]/,
            /(\/etc\/passwd|\/bin\/sh|cmd\.exe|powershell\.exe)/i,
            
            // LDAP injection
            /[()&|!]/,
            
            // NoSQL injection
            /(\$where|\$ne|\$gt|\$lt|\$in|\$nin)/i
        ];

        for (const pattern of dangerousPatterns) {
            if (pattern.test(input)) {
                throw new Error('Input contains potentially dangerous patterns');
            }
        }

        // Context-specific checks
        if (patternName === 'wp_username' && this.isReservedWordPressUsername(input)) {
            throw new Error('Username is reserved');
        }

        if (patternName === 'safe_url' && !this.isAllowedDomain(input)) {
            throw new Error('URL domain not allowed');
        }
    }

    /**
     * HTML sanitization
     * @param {string} input - HTML input
     * @param {Object} rules - Sanitization rules
     * @returns {string} Sanitized HTML
     */
    sanitizeHTML(input, rules) {
        let sanitized = input;

        // Remove script tags and content
        if (rules.stripScripts) {
            sanitized = sanitized.replace(/<script[^>]*>.*?<\/script>/gsi, '');
            sanitized = sanitized.replace(/javascript:/gi, '');
        }

        // Remove style tags and attributes
        if (rules.stripStyles) {
            sanitized = sanitized.replace(/<style[^>]*>.*?<\/style>/gsi, '');
            sanitized = sanitized.replace(/style\s*=\s*["'][^"']*["']/gi, '');
        }

        // Remove comments
        if (rules.stripComments) {
            sanitized = sanitized.replace(/<!--.*?-->/gs, '');
        }

        // Remove event handlers
        sanitized = sanitized.replace(/on\w+\s*=\s*["'][^"']*["']/gi, '');

        // Encode special characters
        sanitized = sanitized
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#x27;');

        return sanitized;
    }

    /**
     * SQL sanitization
     * @param {string} input - SQL input
     * @param {Object} rules - Sanitization rules
     * @returns {string} Sanitized SQL
     */
    sanitizeSQL(input, rules) {
        let sanitized = input;

        // Escape quotes
        if (rules.escapeQuotes) {
            sanitized = sanitized.replace(/'/g, "''");
            sanitized = sanitized.replace(/"/g, '""');
        }

        // Remove SQL comments
        if (rules.stripComments) {
            sanitized = sanitized.replace(/--.*$/gm, '');
            sanitized = sanitized.replace(/\/\*.*?\*\//gs, '');
        }

        // Validate allowed characters
        if (rules.allowedChars && !rules.allowedChars.test(sanitized)) {
            throw new Error('SQL input contains invalid characters');
        }

        return sanitized;
    }

    /**
     * JavaScript sanitization
     * @param {string} input - JavaScript input
     * @param {Object} rules - Sanitization rules
     * @returns {string} Sanitized JavaScript
     */
    sanitizeJavaScript(input, rules) {
        let sanitized = input;

        if (rules.stripScripts) {
            sanitized = sanitized.replace(/<script[^>]*>.*?<\/script>/gsi, '');
        }

        if (rules.stripEvents) {
            sanitized = sanitized.replace(/on\w+\s*=\s*["'][^"']*["']/gi, '');
        }

        if (rules.stripEval) {
            sanitized = sanitized.replace(/eval\s*\(/gi, '');
        }

        return sanitized;
    }

    /**
     * WordPress content sanitization
     * @param {string} input - WordPress content
     * @param {Object} rules - Sanitization rules
     * @returns {string} Sanitized content
     */
    sanitizeWordPressContent(input, rules) {
        // First apply HTML sanitization
        let sanitized = this.sanitizeHTML(input, rules);

        // WordPress-specific cleaning
        sanitized = sanitized.replace(/\[shortcode[^\]]*\]/gi, ''); // Remove shortcodes
        sanitized = sanitized.replace(/\{\{.*?\}\}/g, ''); // Remove template syntax

        return sanitized;
    }

    /**
     * Generic sanitization for unknown contexts
     * @param {string} input - Input to sanitize
     * @returns {string} Sanitized input
     */
    sanitizeGeneric(input) {
        return input
            .replace(/[<>&"']/g, (match) => {
                const entities = {
                    '<': '&lt;',
                    '>': '&gt;',
                    '&': '&amp;',
                    '"': '&quot;',
                    "'": '&#x27;'
                };
                return entities[match] || match;
            })
            .trim();
    }

    /**
     * Validate file uploads
     * @param {Object} fileInfo - File information
     * @returns {Object} Validation result
     */
    validateFileUpload(fileInfo) {
        const { filename, size, mimetype } = fileInfo;

        // Validate filename
        const filenameValidation = this.validate(filename, 'safe_filename');
        if (!filenameValidation.valid) {
            return filenameValidation;
        }

        // Size limits
        const maxSize = 10 * 1024 * 1024; // 10MB
        if (size > maxSize) {
            return {
                valid: false,
                error: 'File too large (maximum 10MB)'
            };
        }

        // MIME type validation
        const allowedMimes = [
            'image/jpeg',
            'image/png',
            'image/gif',
            'application/pdf',
            'text/plain'
        ];

        if (!allowedMimes.includes(mimetype)) {
            return {
                valid: false,
                error: 'File type not allowed'
            };
        }

        return {
            valid: true,
            filename: filenameValidation.sanitized
        };
    }

    /**
     * WordPress-specific validation helpers
     */

    /**
     * Validate WordPress nonce
     * @param {string} nonce - Nonce value
     * @param {string} action - Action name
     * @returns {boolean} Validation result
     */
    validateWordPressNonce(nonce, action) {
        const validation = this.validate(nonce, 'wp_nonce');
        if (!validation.valid) {
            return false;
        }

        // Additional WordPress nonce validation would go here
        // This would typically verify against WordPress's nonce system
        return true;
    }

    /**
     * Validate WordPress capability
     * @param {string} capability - Capability name
     * @returns {boolean} Validation result
     */
    validateWordPressCapability(capability) {
        const allowedCapabilities = [
            'read',
            'edit_posts',
            'edit_others_posts',
            'publish_posts',
            'manage_options',
            'manage_hvac_trainers',
            'manage_hvac_events',
            'view_hvac_reports'
        ];

        return allowedCapabilities.includes(capability);
    }

    /**
     * Utility methods
     */

    generateValidationId() {
        return crypto.randomUUID();
    }

    isReservedWordPressUsername(username) {
        const reserved = ['admin', 'administrator', 'root', 'test', 'guest', 'user'];
        return reserved.includes(username.toLowerCase());
    }

    isAllowedDomain(url) {
        try {
            const urlObj = new URL(url);
            const allowedDomains = [
                'measurequick.com',
                'upskill-staging.measurequick.com'
            ];
            return allowedDomains.some(domain => urlObj.hostname.endsWith(domain));
        } catch {
            return false;
        }
    }

    logValidation(validationId, pattern, status, details) {
        const logEntry = {
            validationId,
            timestamp: new Date().toISOString(),
            pattern,
            status,
            ...details
        };

        this.validationLog.push(logEntry);
        this.credentialManager.auditLogger('INPUT_VALIDATION', logEntry);
    }

    logSanitization(context, originalLength, sanitizedLength) {
        this.credentialManager.auditLogger('INPUT_SANITIZATION', {
            context,
            originalLength,
            sanitizedLength,
            reductionRatio: ((originalLength - sanitizedLength) / originalLength) * 100
        });
    }

    /**
     * Get validation audit log
     * @returns {Array} Validation log
     */
    getValidationLog() {
        return [...this.validationLog];
    }

    /**
     * Clear validation log
     */
    clearValidationLog() {
        this.validationLog = [];
    }
}

// Singleton instance
let inputValidatorInstance = null;

/**
 * Get singleton instance of SecureInputValidator
 * @returns {SecureInputValidator}
 */
function getInputValidator() {
    if (!inputValidatorInstance) {
        inputValidatorInstance = new SecureInputValidator();
    }
    return inputValidatorInstance;
}

module.exports = {
    SecureInputValidator,
    getInputValidator
};