// middleware/checkResourcePermission.js
const User = require('../models/userSchema');
const AuditLog = require('../models/auditLogSchema');

/**
 * Dynamic Resource Permission Middleware
 * Checks if user has permission for a specific resource and action
 * 
 * @param {string} resourceName - Name of the resource (e.g., 'users', 'kyc_sessions')
 * @param {string} action - Action to check ('view', 'add', 'edit', 'delete')
 * @param {object} options - Additional options for permission checking
 */
const checkPermission = (resourceName, action, options = {}) => {
  return async (req, res, next) => {
    try {
      // Ensure user is authenticated
      if (!req.user) {
        return res.status(401).json({ 
          error: 'Authentication required',
          code: 'AUTHENTICATION_REQUIRED'
        });
      }

      // Fetch user with populated role and permissions
      const user = await User.findById(req.user.userId)
        .populate({
          path: 'role',
          populate: {
            path: 'permissions.resource',
            model: 'Resource'
          }
        });


      if (!user) {
        return res.status(404).json({ 
          error: 'User not found',
          code: 'USER_NOT_FOUND'
        });
      }

      if (!user.role) {
        return res.status(403).json({ 
          error: 'Access denied: No role assigned',
          code: 'NO_ROLE_ASSIGNED'
        });
      }

      if (!user.role.isActive) {
        return res.status(403).json({ 
          error: 'Access denied: Role is inactive',
          code: 'ROLE_INACTIVE'
        });
      }

      // Find the permission for the requested resource
      const resourcePermission = user.role.permissions.find(perm => 
        perm.resource && perm.resource.name === resourceName
      );

      if (!resourcePermission) {
        // Log unauthorized access attempt
        await logUnauthorizedAccess(req, user, resourceName, action, 'NO_RESOURCE_PERMISSION');
        
        return res.status(403).json({ 
          error: `Access denied: No permission for resource '${resourceName}'`,
          code: 'NO_RESOURCE_PERMISSION',
          resource: resourceName,
          userRole: user.role.displayName,
          userId: user._id
        });
      }

      // Check if the specific action is allowed
      if (!resourcePermission.actions.includes(action)) {
        // Log unauthorized access attempt
        await logUnauthorizedAccess(req, user, resourceName, action, 'ACTION_NOT_PERMITTED');
        
        return res.status(403).json({ 
          error: `Access denied: Action '${action}' not permitted on resource '${resourceName}'`,
          code: 'ACTION_NOT_PERMITTED',
          resource: resourceName,
          action: action,
          allowedActions: resourcePermission.actions,
          userRole: user.role.displayName,
          userId: user._id
        });
      }

      // Add permission context to request for later use
      req.userPermission = {
        resource: resourceName,
        action: action,
        resourceId: resourcePermission.resource._id,
        allowedActions: resourcePermission.actions,
        role: user.role,
        user: {
          id: user._id,
          name: user.name,
          email: user.email
        }
      };

      next();
    } catch (error) {
      console.error('Permission check error:', error);
      res.status(500).json({ 
        error: 'Internal server error during permission check',
        code: 'PERMISSION_CHECK_FAILED'
      });
    }
  };
};

/**
 * Helper function to log unauthorized access attempts
 */
const logUnauthorizedAccess = async (req, user, resourceName, action, reasonCode) => {
  try {
    await AuditLog.create({
      userId: user._id,
      action: action,
      ipAddress: req.ip,
    });
  } catch (logError) {
    console.error('Failed to log unauthorized access:', logError);
  }
};

module.exports = checkPermission;
