const { ROLE_HIERARCHY, requireRole } = require('../middleware/rbac');

/**
 * Unit Tests for RBAC Logic (No Database Required)
 * Tests role hierarchy and permission checking logic
 */

describe('RBAC Unit Tests', () => {
  describe('ROLE_HIERARCHY', () => {
    test('should have correct role hierarchy levels', () => {
      expect(ROLE_HIERARCHY.super_admin).toBe(3);
      expect(ROLE_HIERARCHY.admin).toBe(2);
      expect(ROLE_HIERARCHY.operator).toBe(1);
    });

    test('super_admin should have highest level', () => {
      expect(ROLE_HIERARCHY.super_admin).toBeGreaterThan(ROLE_HIERARCHY.admin);
      expect(ROLE_HIERARCHY.super_admin).toBeGreaterThan(ROLE_HIERARCHY.operator);
    });

    test('admin should have higher level than operator', () => {
      expect(ROLE_HIERARCHY.admin).toBeGreaterThan(ROLE_HIERARCHY.operator);
    });
  });

  describe('requireRole middleware', () => {
    let req, res, next;

    beforeEach(() => {
      req = {
        admin: null,
        path: '/test',
      };
      res = {
        status: jest.fn().mockReturnThis(),
        json: jest.fn().mockReturnThis(),
      };
      next = jest.fn();
    });

    test('should reject request without admin', () => {
      const middleware = requireRole(['operator']);
      middleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(401);
      expect(res.json).toHaveBeenCalledWith(
        expect.objectContaining({
          success: false,
          error: expect.objectContaining({
            code: 'UNAUTHORIZED',
          }),
        })
      );
      expect(next).not.toHaveBeenCalled();
    });

    test('should allow admin with exact role match', () => {
      req.admin = { username: 'testadmin', role: 'admin' };
      const middleware = requireRole(['admin']);
      middleware(req, res, next);

      expect(next).toHaveBeenCalled();
      expect(res.status).not.toHaveBeenCalled();
    });

    test('should allow admin with higher role', () => {
      req.admin = { username: 'superadmin', role: 'super_admin' };
      const middleware = requireRole(['admin']);
      middleware(req, res, next);

      expect(next).toHaveBeenCalled();
      expect(res.status).not.toHaveBeenCalled();
    });

    test('should deny admin with lower role', () => {
      req.admin = { username: 'operator', role: 'operator' };
      const middleware = requireRole(['admin']);
      middleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(403);
      expect(res.json).toHaveBeenCalledWith(
        expect.objectContaining({
          success: false,
          error: expect.objectContaining({
            code: 'FORBIDDEN',
          }),
        })
      );
      expect(next).not.toHaveBeenCalled();
    });

    test('should allow any role in allowed roles array', () => {
      req.admin = { username: 'operator', role: 'operator' };
      const middleware = requireRole(['operator', 'admin', 'super_admin']);
      middleware(req, res, next);

      expect(next).toHaveBeenCalled();
      expect(res.status).not.toHaveBeenCalled();
    });

    test('should handle multiple allowed roles correctly', () => {
      req.admin = { username: 'admin', role: 'admin' };
      const middleware = requireRole(['admin', 'super_admin']);
      middleware(req, res, next);

      expect(next).toHaveBeenCalled();
      expect(res.status).not.toHaveBeenCalled();
    });
  });

  describe('Role permission scenarios', () => {
    test('super_admin can access operator-level endpoints', () => {
      const req = { admin: { role: 'super_admin', username: 'super' }, path: '/test' };
      const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
      const next = jest.fn();

      const middleware = requireRole(['operator']);
      middleware(req, res, next);

      expect(next).toHaveBeenCalled();
    });

    test('super_admin can access admin-level endpoints', () => {
      const req = { admin: { role: 'super_admin', username: 'super' }, path: '/test' };
      const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
      const next = jest.fn();

      const middleware = requireRole(['admin']);
      middleware(req, res, next);

      expect(next).toHaveBeenCalled();
    });

    test('admin can access operator-level endpoints', () => {
      const req = { admin: { role: 'admin', username: 'admin' }, path: '/test' };
      const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
      const next = jest.fn();

      const middleware = requireRole(['operator']);
      middleware(req, res, next);

      expect(next).toHaveBeenCalled();
    });

    test('admin cannot access super_admin-level endpoints', () => {
      const req = { admin: { role: 'admin', username: 'admin' }, path: '/test' };
      const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
      const next = jest.fn();

      const middleware = requireRole(['super_admin']);
      middleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(403);
      expect(next).not.toHaveBeenCalled();
    });

    test('operator cannot access admin-level endpoints', () => {
      const req = { admin: { role: 'operator', username: 'op' }, path: '/test' };
      const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
      const next = jest.fn();

      const middleware = requireRole(['admin']);
      middleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(403);
      expect(next).not.toHaveBeenCalled();
    });

    test('operator cannot access super_admin-level endpoints', () => {
      const req = { admin: { role: 'operator', username: 'op' }, path: '/test' };
      const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
      const next = jest.fn();

      const middleware = requireRole(['super_admin']);
      middleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(403);
      expect(next).not.toHaveBeenCalled();
    });
  });
});
