const jwt = require('jsonwebtoken');
const User = require('../models/User');
const logger = require('../config/logger');
const { promisify } = require('util');

const protect = async (req, res, next) => {
  try {
    const authHeader = req.headers.authorization;
    if (!authHeader?.startsWith('Bearer ')) {
      return res.status(401).json({
        status: 'error',
        message: 'Authentication required'
      });
    }

    const token = authHeader.split(' ')[1];
    const decoded = await promisify(jwt.verify)(token, process.env.JWT_SECRET);

    const user = await User.findByPk(decoded.id, {
      attributes: { exclude: ['password', 'passwordResetToken', 'passwordResetExpires'] }
    });

    if (!user || !user.isActive) {
      return res.status(401).json({
        status: 'error',
        message: 'User not found or inactive'
      });
    }

    if (user.passwordChangedAfter(decoded.iat)) {
      return res.status(401).json({
        status: 'error',
        message: 'Password was changed. Please login again'
      });
    }

    req.user = user;
    next();
  } catch (error) {
    logger.error('Authentication error:', { error: error.message, stack: error.stack });
    return res.status(401).json({
      status: 'error',
      message: 'Invalid or expired token'
    });
  }
};

const authorize = (...roles) => {
  return (req, res, next) => {
    if (!roles.includes(req.user.role)) {
      logger.warn(`Unauthorized access attempt by user ${req.user.id} to restricted route`);
      return res.status(403).json({
        status: 'error',
        message: 'Not authorized to access this route'
      });
    }
    next();
  };
};

const rateLimiter = async (req, user) => {
  if (user.failedLoginAttempts >= 5) {
    const lockUntil = new Date(Date.now() + 15 * 60 * 1000);
    await user.update({
      lockUntil,
      failedLoginAttempts: 0
    });
    throw new Error('Account locked. Try again in 15 minutes');
  }
};

module.exports = { protect, authorize, rateLimiter };