const jwt = require('jsonwebtoken');
const { UnauthorizedError } = require('../utils/errors');
const User = require('../models/User');

/**
 * Middleware to verify JWT token and attach user to request
 */
const auth = async (req, res, next) => {
  try {
    // Get token from header
    const authHeader = req.header('Authorization');
    console.log('Auth Header:', authHeader); // Debug log
    
    if (!authHeader) {
      console.log('No Authorization header found');
      throw new UnauthorizedError('No token provided');
    }
    
    if (!authHeader.startsWith('Bearer ')) {
      console.log('Invalid Authorization header format. Expected "Bearer <token>"');
      throw new UnauthorizedError('Invalid token format');
    }
    
    const token = authHeader.split(' ')[1];
    
    if (!token) {
      console.log('No token found in Authorization header');
      throw new UnauthorizedError('No token provided');
    }
    
    // Verify token
    let decoded;
    try {
      decoded = jwt.verify(token, process.env.JWT_SECRET);
      console.log('Token decoded successfully:', { userId: decoded.id });
    } catch (verifyError) {
      console.error('Token verification failed:', verifyError.message);
      if (verifyError.name === 'TokenExpiredError') {
        throw new UnauthorizedError('Token expired');
      }
      throw new UnauthorizedError('Invalid token');
    }
    
    // Get user from database and check if still exists and is active
    const user = await User.findById(decoded.id).select('-password');
    
    if (!user) {
      console.log('User not found for id:', decoded.id);
      throw new UnauthorizedError('User no longer exists');
    }
    
    if (user.status === false) {
      console.log('User account is inactive:', user._id);
      throw new UnauthorizedError('User account is inactive');
    }
    
    // If user is a picker_packer, get their store information
    if (user.role === 'picker_packer') {
      const PickerPacker = require('../models/PickerPacker');
      const pickerPacker = await PickerPacker.findOne({ user: user._id })
        .populate('store', 'name _id')
        .lean();
      
      if (pickerPacker && pickerPacker.store) {
        user.store = pickerPacker.store;
        console.log('Picker/Packer store set:', pickerPacker.store);
      } else {
        console.log('No store assigned to picker/packer:', user._id);
      }
    }
    
    // Define role-based redirect paths
    const roleRedirects = {
      superadmin: '/admin/dashboard',
      admin: '/admin/dashboard',
      store_manager: '/store/dashboard',
      pharmacist: '/pharmacist/dashboard',
      picker_packer: '/picker-packer/dashboard',
      delivery_boy: '/delivery/dashboard',
      delivery: '/delivery/dashboard', // For backward compatibility
      customer: '/'
    };

    // Prepare user data for request
    const userData = user.toObject();
    
    // Handle store reference for store managers
    if (user.role === 'store_manager') {
      try {
        // If we already have store data from the login response, use it
        if (user.store) {
          userData.store = user.store;
        } 
        // Otherwise, try to find the store using the storeManager field
        else if (user._id) {
          const Store = require('../models/Store');
          const store = await Store.findOne({ storeManager: user._id });
          if (store) {
            userData.store = {
              _id: store._id,
              name: store.name,
              logo: store.logo
            };
            userData.storeManager = user._id;
          }
        }
        
        // Fallback to existing storeManager if store is still not set
        if (!userData.store && user.storeManager) {
          userData.store = { _id: user.storeManager };
        }
        // Ensure store is an object with _id if it's a string
        else if (userData.store && typeof userData.store === 'string') {
          userData.store = { _id: userData.store };
        }
        
        console.log('Processed store data for store manager:', {
          store: userData.store,
          storeManager: userData.storeManager || user._id,
          role: user.role
        });
      } catch (error) {
        console.error('Error processing store manager data:', error);
        // Don't fail the request, just log the error
      }
    }
    
    // Attach user to request object
    req.user = userData;
    req.userId = user._id;
    req.userRole = user.role;
    
    console.log('Authenticated user store:', userData.store);
    
    next();
  } catch (error) {
    if (error.name === 'JsonWebTokenError') {
      return next(new UnauthorizedError('Invalid token'));
    }
    if (error.name === 'TokenExpiredError') {
      return next(new UnauthorizedError('Token expired'));
    }
    next(error);
  }
};

/**
 * Middleware to check if user has one of the specified roles
 * @param {...string} roles - Allowed roles
 * @returns {Function} Express middleware function
 */
const authorize = (...roles) => {
  return (req, res, next) => {
    try {
      if (!req.user) {
        throw new UnauthorizedError('Authentication required');
      }
      
      // Super admin has access to everything
      if (req.user.role === 'superadmin') {
        return next();
      }
      
      if (roles.length > 0 && !roles.includes(req.user.role)) {
        throw new UnauthorizedError(
          `User role ${req.user.role} is not authorized to access this route`
        );
      }
      
      next();
    } catch (error) {
      next(error);
    }
  };
};

// Middleware to check if the user is the owner of the resource
const isOwner = (model, paramName = 'id') => {
  return async (req, res, next) => {
    try {
      // Skip check for admin
      if (req.user.role === 'admin') {
        return next();
      }
      
      // Get the resource
      const resource = await model.findById(req.params[paramName]);
      
      // Check if resource exists
      if (!resource) {
        return res.status(404).json({ 
          success: false, 
          msg: 'Resource not found' 
        });
      }
      
      // Check if user is the owner
      if (resource.user_id.toString() !== req.user.id) {
        return res.status(403).json({ 
          success: false, 
          msg: 'Not authorized to access this resource' 
        });
      }
      
      // Add resource to request object for use in the route handler
      req.resource = resource;
      next();
    } catch (error) {
      console.error('Error in isOwner middleware:', error);
      res.status(500).json({ 
        success: false, 
        msg: 'Server error' 
      });
    }
  };
};

// Middleware to verify email
const verifyEmail = async (req, res, next) => {
  try {
    // Get user from database
    const user = await User.findById(req.user.id);
    
    if (!user) {
      return res.status(404).json({ 
        success: false, 
        msg: 'User not found' 
      });
    }
    
    // Check if email is verified
    if (!user.is_email_verified) {
      return res.status(403).json({ 
        success: false, 
        msg: 'Please verify your email address' 
      });
    }
    
    next();
  } catch (error) {
    console.error('Error in verifyEmail middleware:', error);
    res.status(500).json({ 
      success: false, 
      msg: 'Server error' 
    });
  }
};

module.exports = {
  auth,
  authorize,
  isOwner,
  verifyEmail
};
