/**
 * Route Protection Utility
 * Ensures all routes have proper error handling (CWE-391 compliance)
 * Wraps database callbacks and async operations with error handlers
 */

const logger = require('./logger');
const { sanitizeError } = require('./errorHandler');

/**
 * Wrap database callback to ensure errors are caught
 * 
 * @param {Function} callback - Database callback function
 * @param {Object} res - Express response object
 * @param {string} context - Context for error logging
 * @returns {Function} Wrapped callback
 */
function wrapDbCallback(callback, res, context = 'Database operation') {
  return function(err, ...args) {
    if (err) {
      logger.error(`${context} error:`, {
        error: err.message,
        stack: err.stack,
        context
      });
      
      const sanitized = sanitizeError(err);
      return res.status(500).json({
        error: sanitized.message,
        code: sanitized.code,
        timestamp: new Date().toISOString()
      });
    }
    
    try {
      return callback(err, ...args);
    } catch (callbackError) {
      logger.error(`${context} callback error:`, {
        error: callbackError.message,
        stack: callbackError.stack,
        context
      });
      
      const sanitized = sanitizeError(callbackError);
      return res.status(500).json({
        error: sanitized.message,
        code: sanitized.code,
        timestamp: new Date().toISOString()
      });
    }
  };
}

/**
 * Wrap sync route handler to catch any errors
 * 
 * @param {Function} handler - Route handler function
 * @returns {Function} Wrapped handler
 */
function wrapSyncHandler(handler) {
  return function(req, res, next) {
    try {
      return handler(req, res, next);
    } catch (error) {
      logger.error('Sync route handler error:', {
        error: error.message,
        stack: error.stack,
        method: req.method,
        path: req.path
      });
      
      next(error);
    }
  };
}

/**
 * Wrap async route handler to catch promise rejections
 * 
 * @param {Function} handler - Async route handler function
 * @returns {Function} Wrapped handler
 */
function wrapAsyncHandler(handler) {
  return function(req, res, next) {
    Promise.resolve(handler(req, res, next))
      .catch((error) => {
        logger.error('Async route handler error:', {
          error: error.message,
          stack: error.stack,
          method: req.method,
          path: req.path
        });
        
        next(error);
      });
  };
}

/**
 * Smart route wrapper - automatically detects and wraps handlers
 * 
 * @param {Function} handler - Route handler (sync or async)
 * @returns {Function} Wrapped handler
 */
function protectRoute(handler) {
  // Check if handler is async
  if (handler.constructor.name === 'AsyncFunction') {
    return wrapAsyncHandler(handler);
  }
  
  return wrapSyncHandler(handler);
}

/**
 * Protect all routes in a router
 * 
 * @param {Object} router - Express router
 * @param {Array} routes - Array of route definitions
 */
function protectAllRoutes(router, routes) {
  routes.forEach(({ method, path, middleware = [], handler }) => {
    const wrappedHandler = protectRoute(handler);
    router[method](path, ...middleware, wrappedHandler);
  });
}

/**
 * Create a safe database wrapper with automatic error handling
 * 
 * @param {Object} db - Database connection
 * @returns {Object} Wrapped database object
 */
function createSafeDb(db) {
  return {
    // Wrap db.run
    run: (sql, params, callback) => {
      try {
        return db.run(sql, params, (err, ...args) => {
          if (err) {
            logger.error('Database run error:', {
              error: err.message,
              sql: sql.substring(0, 100) // Log first 100 chars only
            });
          }
          if (callback) {
            try {
              return callback(err, ...args);
            } catch (callbackError) {
              logger.error('Database run callback error:', callbackError);
            }
          }
        });
      } catch (error) {
        logger.error('Database run exception:', error);
        if (callback) {
          callback(error);
        }
      }
    },
    
    // Wrap db.get
    get: (sql, params, callback) => {
      try {
        return db.get(sql, params, (err, ...args) => {
          if (err) {
            logger.error('Database get error:', {
              error: err.message,
              sql: sql.substring(0, 100)
            });
          }
          if (callback) {
            try {
              return callback(err, ...args);
            } catch (callbackError) {
              logger.error('Database get callback error:', callbackError);
            }
          }
        });
      } catch (error) {
        logger.error('Database get exception:', error);
        if (callback) {
          callback(error);
        }
      }
    },
    
    // Wrap db.all
    all: (sql, params, callback) => {
      try {
        return db.all(sql, params, (err, ...args) => {
          if (err) {
            logger.error('Database all error:', {
              error: err.message,
              sql: sql.substring(0, 100)
            });
          }
          if (callback) {
            try {
              return callback(err, ...args);
            } catch (callbackError) {
              logger.error('Database all callback error:', callbackError);
            }
          }
        });
      } catch (error) {
        logger.error('Database all exception:', error);
        if (callback) {
          callback(error);
        }
      }
    },
    
    // Pass through other methods
    close: (...args) => db.close(...args),
    serialize: (...args) => db.serialize(...args),
    parallelize: (...args) => db.parallelize(...args)
  };
}

module.exports = {
  wrapDbCallback,
  wrapSyncHandler,
  wrapAsyncHandler,
  protectRoute,
  protectAllRoutes,
  createSafeDb
};
