/**
 * Allows Admin or User. Use for listing users (e.g. audit dropdowns) and external auditors.
 * Auditor role has been removed; User role can list users/external auditors for Create/Update Audit.
 * Accepts role names (roles) or role IDs (roleIds) from JWT; if missing, fetches roles from DB.
 */
const { ROLE_IDS } = require('../constants/hseRoles');

const ADMIN_ROLE_ID = ROLE_IDS.ADMIN;
const USER_ROLE_ID = ROLE_IDS.USER;

const normalizeRoleNames = (roles) => {
  if (Array.isArray(roles)) return roles.map((r) => String(r || '').toLowerCase());
  if (typeof roles === 'string') return roles.split(',').map((s) => s.trim().toLowerCase());
  return [];
};

const checkAllowedFromToken = (req) => {
  const userRoles = normalizeRoleNames(req.user.roles || []);
  const roleIds = (req.user.roleIds || []).map((id) => Number(id)).filter((n) => !Number.isNaN(n));

  const isAdminByName = userRoles.includes('admin');
  const isUserByName = userRoles.includes('user');
  const isAdminById = roleIds.includes(ADMIN_ROLE_ID);
  const isUserById = roleIds.includes(USER_ROLE_ID);

  return isAdminByName || isUserByName || isAdminById || isUserById;
};

const verifyAdminOrAuditor = async (req, res, next) => {
  const runNext = () => next();
  const send403 = () =>
    res.status(403).json({
      success: false,
      message: 'Access denied. Admin or User privileges required.'
    });

  try {
    if (!req.user) {
      return res.status(401).json({
        success: false,
        message: 'Access denied. User not authenticated.'
      });
    }

    if (checkAllowedFromToken(req)) return runNext();

    // Token missing or invalid role info – resolve from DB
    try {
      const { getUserById } = require('../repositories/userRepository');
      const userId = req.user.userId || req.user.user_id;
      if (!userId) return send403();

      const user = await getUserById(userId);
      if (!user || !(user.roles && user.roles.length)) return send403();

      const roleIds = (user.roles || []).map((r) => Number(r.role_id)).filter((n) => !Number.isNaN(n));
      const roleNames = normalizeRoleNames((user.roles || []).map((r) => (r && (r.role_name ?? r.roleName)) || ''));

      const allowed =
        roleIds.includes(ADMIN_ROLE_ID) ||
        roleIds.includes(USER_ROLE_ID) ||
        roleNames.includes('admin') ||
        roleNames.includes('user');

      if (allowed) return runNext();
      return send403();
    } catch (err) {
      console.error('Admin/User verification DB fallback error:', err);
      return send403();
    }
  } catch (error) {
    console.error('Admin/User verification error:', error);
    return res.status(500).json({
      success: false,
      message: 'Verification failed',
      error: error.message
    });
  }
};

module.exports = verifyAdminOrAuditor;
