const jwt = require('jsonwebtoken');
const { User, Role, Permission } = require('../models/foundation');

exports.protect = async (req, res, next) => {
    let token;
    if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
        token = req.headers.authorization.split(' ')[1];
    } else if (req.query.token) {
        token = req.query.token;
    }

    if (!token) {
        return res.status(401).json({ message: 'Not authorized to access this route' });
    }

    try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);

        // Fetch fresh user data with role and permissions
        const user = await User.findByPk(decoded.id, {
            include: [{
                model: Role,
                include: [{ model: Permission }]
            }]
        });

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

        req.user = user;
        req.userRole = user.Role.constant;
        req.userPermissions = user.Role.Permissions.map(p => p.name);

        next();
    } catch (err) {
        return res.status(401).json({ message: 'Token is invalid or expired' });
    }
};

/**
 * Authorize based on roles or specific permissions
 * @param  {...string} requirements - Role constants (e.g. 'ADMIN') or Permission names (e.g. 'VIEW_INVOICES')
 */
exports.authorize = (...requirements) => {
    return (req, res, next) => {
        const hasRole = requirements.includes(req.userRole);
        const hasPermission = requirements.some(r => req.userPermissions.includes(r));

        // Super Admin always bypasses
        if (req.userRole === 'SUPER_ADMIN') return next();

        if (!hasRole && !hasPermission) {
            return res.status(403).json({
                message: `Access denied. You do not have the required role or permission.`
            });
        }
        next();
    };
};

/**
 * Middleware to isolate data for CLIENT role users.
 * If user is a CLIENT, it ensures they only see their own data.
 */
exports.isolateClient = (req, res, next) => {
    if (req.userRole === 'CLIENT') {
        if (!req.user.clientId) {
            return res.status(403).json({ message: 'Client profile not mapped to user' });
        }
        // Inject clientId into query/body for filtration in services
        req.query.clientId = req.user.clientId;
        req.body.clientId = req.user.clientId; // Prevent spoofing clientId in forms
    }
    next();
};
