"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ValidationMiddleware = void 0;
const ErrorResponseService_1 = require("./ErrorResponseService");
const Logger_1 = require("./Logger");
/**
 * Common validation middleware functions for request validation
 */
class ValidationMiddleware {
    /**
     * Validates required fields in request body
     * @param requiredFields Array of required field names
     */
    static validateRequiredFields(requiredFields) {
        return (req, res, next) => {
            const missingFields = [];
            for (const field of requiredFields) {
                if (!req.body || req.body[field] === undefined || req.body[field] === null || req.body[field] === '') {
                    missingFields.push(field);
                }
            }
            if (missingFields.length > 0) {
                (0, Logger_1.logWarning)('Validation failed - missing required fields', {
                    missingFields,
                    endpoint: req.path
                }, req, res);
                return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Missing required fields', { missingFields });
            }
            next();
        };
    }
    /**
     * Validates field types in request body
     * @param fieldTypes Object mapping field names to expected types
     */
    static validateFieldTypes(fieldTypes) {
        return (req, res, next) => {
            const typeErrors = [];
            for (const [field, expectedType] of Object.entries(fieldTypes)) {
                if (req.body && req.body[field] !== undefined) {
                    const actualType = Array.isArray(req.body[field]) ? 'array' : typeof req.body[field];
                    if (actualType !== expectedType) {
                        typeErrors.push(`Field '${field}' should be ${expectedType}, got ${actualType}`);
                    }
                }
            }
            if (typeErrors.length > 0) {
                (0, Logger_1.logWarning)('Validation failed - invalid field types', {
                    typeErrors,
                    endpoint: req.path
                }, req, res);
                return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Invalid field types', { errors: typeErrors });
            }
            next();
        };
    }
    /**
     * Validates string field length constraints
     * @param constraints Object mapping field names to min/max length
     */
    static validateStringLength(constraints) {
        return (req, res, next) => {
            const lengthErrors = [];
            for (const [field, constraint] of Object.entries(constraints)) {
                if (req.body && typeof req.body[field] === 'string') {
                    const value = req.body[field];
                    if (constraint.min !== undefined && value.length < constraint.min) {
                        lengthErrors.push(`Field '${field}' must be at least ${constraint.min} characters`);
                    }
                    if (constraint.max !== undefined && value.length > constraint.max) {
                        lengthErrors.push(`Field '${field}' must not exceed ${constraint.max} characters`);
                    }
                }
            }
            if (lengthErrors.length > 0) {
                (0, Logger_1.logWarning)('Validation failed - string length constraints', {
                    lengthErrors,
                    endpoint: req.path
                }, req, res);
                return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'String length validation failed', { errors: lengthErrors });
            }
            next();
        };
    }
    /**
     * Validates email format
     * @param emailFields Array of field names that should contain valid emails
     */
    static validateEmailFormat(emailFields) {
        return (req, res, next) => {
            const emailErrors = [];
            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            for (const field of emailFields) {
                if (req.body && req.body[field] && typeof req.body[field] === 'string') {
                    if (!emailRegex.test(req.body[field])) {
                        emailErrors.push(`Field '${field}' must contain a valid email address`);
                    }
                }
            }
            if (emailErrors.length > 0) {
                (0, Logger_1.logWarning)('Validation failed - invalid email format', {
                    emailErrors,
                    endpoint: req.path
                }, req, res);
                return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Email format validation failed', { errors: emailErrors });
            }
            next();
        };
    }
    /**
     * Validates UUIDs format
     * @param uuidFields Array of field names that should contain valid UUIDs
     */
    static validateUUIDFormat(uuidFields) {
        return (req, res, next) => {
            const uuidErrors = [];
            const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
            for (const field of uuidFields) {
                const value = field.includes('.')
                    ? this.getNestedValue(req, field)
                    : req.body?.[field] || req.params?.[field] || req.query?.[field];
                if (value && typeof value === 'string') {
                    if (!uuidRegex.test(value)) {
                        uuidErrors.push(`Field '${field}' must contain a valid UUID`);
                    }
                }
            }
            if (uuidErrors.length > 0) {
                (0, Logger_1.logWarning)('Validation failed - invalid UUID format', {
                    uuidErrors,
                    endpoint: req.path
                }, req, res);
                return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'UUID format validation failed', { errors: uuidErrors });
            }
            next();
        };
    }
    /**
     * Validates numeric constraints
     * @param constraints Object mapping field names to min/max values
     */
    static validateNumericConstraints(constraints) {
        return (req, res, next) => {
            const numericErrors = [];
            for (const [field, constraint] of Object.entries(constraints)) {
                if (req.body && typeof req.body[field] === 'number') {
                    const value = req.body[field];
                    if (constraint.min !== undefined && value < constraint.min) {
                        numericErrors.push(`Field '${field}' must be at least ${constraint.min}`);
                    }
                    if (constraint.max !== undefined && value > constraint.max) {
                        numericErrors.push(`Field '${field}' must not exceed ${constraint.max}`);
                    }
                }
            }
            if (numericErrors.length > 0) {
                (0, Logger_1.logWarning)('Validation failed - numeric constraints', {
                    numericErrors,
                    endpoint: req.path
                }, req, res);
                return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Numeric validation failed', { errors: numericErrors });
            }
            next();
        };
    }
    /**
     * Validates that arrays are not empty
     * @param arrayFields Array of field names that should contain non-empty arrays
     */
    static validateNonEmptyArrays(arrayFields) {
        return (req, res, next) => {
            const arrayErrors = [];
            for (const field of arrayFields) {
                if (req.body && Array.isArray(req.body[field])) {
                    if (req.body[field].length === 0) {
                        arrayErrors.push(`Field '${field}' must not be empty`);
                    }
                }
                else if (req.body && req.body[field] !== undefined) {
                    arrayErrors.push(`Field '${field}' must be an array`);
                }
            }
            if (arrayErrors.length > 0) {
                (0, Logger_1.logWarning)('Validation failed - empty arrays', {
                    arrayErrors,
                    endpoint: req.path
                }, req, res);
                return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Array validation failed', { errors: arrayErrors });
            }
            next();
        };
    }
    /**
     * Validates allowed values for enum-like fields
     * @param allowedValues Object mapping field names to arrays of allowed values
     */
    static validateAllowedValues(allowedValues) {
        return (req, res, next) => {
            const valueErrors = [];
            for (const [field, allowed] of Object.entries(allowedValues)) {
                if (req.body && req.body[field] !== undefined) {
                    if (!allowed.includes(req.body[field])) {
                        valueErrors.push(`Field '${field}' must be one of: ${allowed.join(', ')}`);
                    }
                }
            }
            if (valueErrors.length > 0) {
                (0, Logger_1.logWarning)('Validation failed - disallowed values', {
                    valueErrors,
                    endpoint: req.path
                }, req, res);
                return ErrorResponseService_1.ErrorResponseService.sendBadRequest(res, 'Value validation failed', { errors: valueErrors });
            }
            next();
        };
    }
    /**
     * Combines multiple validation middlewares
     * @param validations Array of validation middleware functions
     */
    static combine(validations) {
        return async (req, res, next) => {
            let currentIndex = 0;
            const runNext = (error) => {
                if (error) {
                    return next(error);
                }
                if (currentIndex >= validations.length) {
                    return next();
                }
                const currentValidation = validations[currentIndex++];
                try {
                    currentValidation(req, res, (err) => {
                        if (res.headersSent) {
                            return; // Response already sent, don't continue
                        }
                        runNext(err);
                    });
                }
                catch (error) {
                    (0, Logger_1.logError)('Validation middleware error', error, req, res);
                    ErrorResponseService_1.ErrorResponseService.sendInternalServerError(res);
                }
            };
            runNext();
        };
    }
    /**
     * Helper method to get nested values from request
     * @param req Request object
     * @param path Dot-notation path like 'body.user.id'
     */
    static getNestedValue(req, path) {
        const parts = path.split('.');
        let current = req;
        for (const part of parts) {
            if (current && typeof current === 'object') {
                current = current[part];
            }
            else {
                return undefined;
            }
        }
        return current;
    }
}
exports.ValidationMiddleware = ValidationMiddleware;
//# sourceMappingURL=ValidationMiddleware.js.map