/**
 * Validation Middleware
 * Provides reusable validation middleware for common request patterns
 */

const {
  validateUsername,
  validateEmail,
  validateUrl,
  validatePlaylistName,
  validateChannelName,
  validateDescription,
  validateFilename,
  validateSettingKey,
  validateInteger,
  validateBoolean,
  validateJSON,
  sanitizeObject
} = require('../utils/inputValidator');
const logger = require('../utils/logger');

/**
 * Generic validation middleware factory
 */
function createValidationMiddleware(validators) {
  return (req, res, next) => {
    const errors = {};
    const sanitized = {};
    let hasErrors = false;

    // Validate body parameters
    if (validators.body) {
      for (const [field, validator] of Object.entries(validators.body)) {
        const value = req.body[field];
        const result = validator(value);
        
        if (!result.valid) {
          errors[field] = result.errors;
          hasErrors = true;
        } else if (result.sanitized !== undefined) {
          sanitized[field] = result.sanitized;
        }
      }
    }

    // Validate query parameters
    if (validators.query) {
      for (const [field, validator] of Object.entries(validators.query)) {
        const value = req.query[field];
        const result = validator(value);
        
        if (!result.valid) {
          errors[`query.${field}`] = result.errors;
          hasErrors = true;
        } else if (result.sanitized !== undefined) {
          if (!req.sanitizedQuery) req.sanitizedQuery = {};
          req.sanitizedQuery[field] = result.sanitized;
        }
      }
    }

    // Validate params
    if (validators.params) {
      for (const [field, validator] of Object.entries(validators.params)) {
        const value = req.params[field];
        const result = validator(value);
        
        if (!result.valid) {
          errors[`params.${field}`] = result.errors;
          hasErrors = true;
        } else if (result.sanitized !== undefined) {
          if (!req.sanitizedParams) req.sanitizedParams = {};
          req.sanitizedParams[field] = result.sanitized;
        }
      }
    }

    if (hasErrors) {
      logger.warn('Validation failed:', { errors, path: req.path, ip: req.ip });
      return res.status(400).json({
        error: 'Validation failed',
        details: errors
      });
    }

    // Replace request data with sanitized versions
    if (Object.keys(sanitized).length > 0) {
      req.body = { ...req.body, ...sanitized };
    }

    next();
  };
}

/**
 * Validate playlist creation/update
 */
const validatePlaylist = createValidationMiddleware({
  body: {
    name: validatePlaylistName,
    url: (value) => validateUrl(value, false),
    category: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: null };
      return validateDescription(value);
    },
    type: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: 'live' };
      const allowed = ['live', 'vod', 'series', 'radio'];
      if (!allowed.includes(value)) {
        return { valid: false, errors: ['Invalid playlist type'], sanitized: null };
      }
      return { valid: true, errors: [], sanitized: value };
    }
  }
});

/**
 * Validate channel update
 */
const validateChannelUpdate = createValidationMiddleware({
  body: {
    name: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: undefined };
      return validateChannelName(value);
    },
    group_name: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: undefined };
      return validateDescription(value);
    }
  }
});

/**
 * Validate settings
 */
const validateSettings = createValidationMiddleware({
  params: {
    key: validateSettingKey
  },
  body: {
    value: (value) => {
      // Settings can be strings, numbers, booleans, or JSON objects
      if (value === undefined || value === null) {
        return { valid: false, errors: ['Value is required'], sanitized: null };
      }
      
      // If it's an object, validate as JSON
      if (typeof value === 'object') {
        return validateJSON(value, 100000);
      }
      
      return { valid: true, errors: [], sanitized: value };
    }
  }
});

/**
 * Validate ID parameter
 */
const validateIdParam = createValidationMiddleware({
  params: {
    id: (value) => validateInteger(value, 1, Number.MAX_SAFE_INTEGER)
  }
});

/**
 * Validate channelId parameter
 */
const validateChannelIdParam = createValidationMiddleware({
  params: {
    channelId: (value) => validateInteger(value, 1, Number.MAX_SAFE_INTEGER)
  }
});

/**
 * Validate pagination parameters
 */
const validatePagination = createValidationMiddleware({
  query: {
    limit: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: 100 };
      return validateInteger(value, 1, 1000);
    },
    offset: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: 0 };
      return validateInteger(value, 0, Number.MAX_SAFE_INTEGER);
    }
  }
});

/**
 * Validate search query
 */
const validateSearch = createValidationMiddleware({
  query: {
    search: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: undefined };
      return validateDescription(value);
    },
    q: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: undefined };
      return validateDescription(value);
    }
  }
});

/**
 * Validate user creation
 */
const validateUserCreation = createValidationMiddleware({
  body: {
    username: validateUsername,
    email: validateEmail,
    password: (value) => {
      if (!value || typeof value !== 'string') {
        return { valid: false, errors: ['Password is required'], sanitized: null };
      }
      if (value.length < 8) {
        return { valid: false, errors: ['Password must be at least 8 characters'], sanitized: null };
      }
      if (value.length > 128) {
        return { valid: false, errors: ['Password must not exceed 128 characters'], sanitized: null };
      }
      return { valid: true, errors: [], sanitized: value };
    },
    role: (value) => {
      const allowed = ['user', 'admin'];
      if (!allowed.includes(value)) {
        return { valid: false, errors: ['Invalid role'], sanitized: null };
      }
      return { valid: true, errors: [], sanitized: value };
    }
  }
});

/**
 * Validate user update
 */
const validateUserUpdate = createValidationMiddleware({
  params: {
    id: (value) => validateInteger(value, 1, Number.MAX_SAFE_INTEGER)
  },
  body: {
    username: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: undefined };
      return validateUsername(value);
    },
    email: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: undefined };
      return validateEmail(value);
    },
    role: (value) => {
      if (!value) return { valid: true, errors: [], sanitized: undefined };
      const allowed = ['user', 'admin'];
      if (!allowed.includes(value)) {
        return { valid: false, errors: ['Invalid role'], sanitized: null };
      }
      return { valid: true, errors: [], sanitized: value };
    },
    is_active: (value) => {
      if (value === undefined) return { valid: true, errors: [], sanitized: undefined };
      return validateBoolean(value);
    }
  }
});

/**
 * Validate filename for file operations
 */
const validateFileOperation = createValidationMiddleware({
  params: {
    filename: validateFilename
  }
});

/**
 * Validate bulk delete operations
 */
const validateBulkDelete = createValidationMiddleware({
  body: {
    ids: (value) => {
      if (!Array.isArray(value)) {
        return { valid: false, errors: ['IDs must be an array'], sanitized: null };
      }
      
      if (value.length === 0) {
        return { valid: false, errors: ['At least one ID required'], sanitized: null };
      }
      
      if (value.length > 1000) {
        return { valid: false, errors: ['Cannot delete more than 1000 items at once'], sanitized: null };
      }
      
      const errors = [];
      const sanitized = [];
      
      for (let i = 0; i < value.length; i++) {
        const result = validateInteger(value[i], 1, Number.MAX_SAFE_INTEGER);
        if (!result.valid) {
          errors.push(`Invalid ID at index ${i}`);
        } else {
          sanitized.push(result.sanitized);
        }
      }
      
      if (errors.length > 0) {
        return { valid: false, errors, sanitized: null };
      }
      
      return { valid: true, errors: [], sanitized };
    }
  }
});

/**
 * Generic text field validator
 */
function validateTextField(maxLength = 1000, required = true) {
  return (value) => {
    if (!value || value === '') {
      if (required) {
        return { valid: false, errors: ['This field is required'], sanitized: null };
      }
      return { valid: true, errors: [], sanitized: '' };
    }
    
    if (typeof value !== 'string') {
      return { valid: false, errors: ['Must be a string'], sanitized: null };
    }
    
    const trimmed = value.trim();
    
    if (required && trimmed.length === 0) {
      return { valid: false, errors: ['This field is required'], sanitized: null };
    }
    
    if (trimmed.length > maxLength) {
      return { valid: false, errors: [`Must not exceed ${maxLength} characters`], sanitized: null };
    }
    
    const result = validateDescription(trimmed);
    return result;
  };
}

module.exports = {
  createValidationMiddleware,
  validatePlaylist,
  validateChannelUpdate,
  validateSettings,
  validateIdParam,
  validateChannelIdParam,
  validatePagination,
  validateSearch,
  validateUserCreation,
  validateUserUpdate,
  validateFileOperation,
  validateBulkDelete,
  validateTextField
};
