"""
Comprehensive tests for state machine guards.

This module contains tests for:
- PermissionGuard (role-based and permission-based)
- OwnershipGuard (ownership verification)
- AssignmentGuard (assignment verification)
- StateGuard (state validation)
- MetadataGuard (required fields validation)
- CompositeGuard (combining guards with AND/OR logic)
"""

from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser
from django.test import TestCase

from apps.core.state_machine.guards import (
    ADMIN_ROLES,
    MODERATOR_ROLES,
    AssignmentGuard,
    CompositeGuard,
    MetadataGuard,
    OwnershipGuard,
    PermissionGuard,
    StateGuard,
    create_assignment_guard,
    create_composite_guard,
    create_ownership_guard,
    create_permission_guard,
    extract_guards_from_metadata,
    get_user_role,
    has_role,
    is_admin_or_above,
    is_moderator_or_above,
    is_superuser_role,
    validate_guard_metadata,
)

User = get_user_model()


class MockInstance:
    """Mock instance for testing guards."""

    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)


# ============================================================================
# PermissionGuard Tests
# ============================================================================


class PermissionGuardTests(TestCase):
    """Tests for PermissionGuard class."""

    def setUp(self):
        """Set up test fixtures."""
        self.regular_user = User.objects.create_user(
            username="user", email="user@example.com", password="testpass123", role="USER"
        )
        self.moderator = User.objects.create_user(
            username="moderator", email="moderator@example.com", password="testpass123", role="MODERATOR"
        )
        self.admin = User.objects.create_user(
            username="admin", email="admin@example.com", password="testpass123", role="ADMIN"
        )
        self.superuser = User.objects.create_user(
            username="superuser", email="superuser@example.com", password="testpass123", role="SUPERUSER"
        )
        self.instance = MockInstance()

    def test_no_user_fails(self):
        """Test that guard fails when no user is provided."""
        guard = PermissionGuard(requires_moderator=True)

        result = guard(self.instance, user=None)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, PermissionGuard.ERROR_CODE_NO_USER)

    def test_requires_moderator_allows_moderator(self):
        """Test that requires_moderator allows moderator role."""
        guard = PermissionGuard(requires_moderator=True)

        result = guard(self.instance, user=self.moderator)

        self.assertTrue(result)

    def test_requires_moderator_allows_admin(self):
        """Test that requires_moderator allows admin role."""
        guard = PermissionGuard(requires_moderator=True)

        result = guard(self.instance, user=self.admin)

        self.assertTrue(result)

    def test_requires_moderator_allows_superuser(self):
        """Test that requires_moderator allows superuser role."""
        guard = PermissionGuard(requires_moderator=True)

        result = guard(self.instance, user=self.superuser)

        self.assertTrue(result)

    def test_requires_moderator_denies_regular_user(self):
        """Test that requires_moderator denies regular user."""
        guard = PermissionGuard(requires_moderator=True)

        result = guard(self.instance, user=self.regular_user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, PermissionGuard.ERROR_CODE_PERMISSION_DENIED_ROLE)

    def test_requires_admin_allows_admin(self):
        """Test that requires_admin allows admin role."""
        guard = PermissionGuard(requires_admin=True)

        result = guard(self.instance, user=self.admin)

        self.assertTrue(result)

    def test_requires_admin_allows_superuser(self):
        """Test that requires_admin allows superuser role."""
        guard = PermissionGuard(requires_admin=True)

        result = guard(self.instance, user=self.superuser)

        self.assertTrue(result)

    def test_requires_admin_denies_moderator(self):
        """Test that requires_admin denies moderator role."""
        guard = PermissionGuard(requires_admin=True)

        result = guard(self.instance, user=self.moderator)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, PermissionGuard.ERROR_CODE_PERMISSION_DENIED_ROLE)

    def test_requires_superuser_allows_superuser(self):
        """Test that requires_superuser allows superuser role."""
        guard = PermissionGuard(requires_superuser=True)

        result = guard(self.instance, user=self.superuser)

        self.assertTrue(result)

    def test_requires_superuser_denies_admin(self):
        """Test that requires_superuser denies admin role."""
        guard = PermissionGuard(requires_superuser=True)

        result = guard(self.instance, user=self.admin)

        self.assertFalse(result)

    def test_required_roles_explicit_list(self):
        """Test using explicit required_roles list."""
        guard = PermissionGuard(required_roles=["ADMIN", "SUPERUSER"])

        self.assertTrue(guard(self.instance, user=self.admin))
        self.assertTrue(guard(self.instance, user=self.superuser))
        self.assertFalse(guard(self.instance, user=self.moderator))
        self.assertFalse(guard(self.instance, user=self.regular_user))

    def test_custom_check_passes(self):
        """Test custom check function that passes."""

        def custom_check(instance, user):
            return hasattr(instance, "allow_access") and instance.allow_access

        guard = PermissionGuard(custom_check=custom_check)
        instance = MockInstance(allow_access=True)

        result = guard(instance, user=self.regular_user)

        self.assertTrue(result)

    def test_custom_check_fails(self):
        """Test custom check function that fails."""

        def custom_check(instance, user):
            return hasattr(instance, "allow_access") and instance.allow_access

        guard = PermissionGuard(custom_check=custom_check)
        instance = MockInstance(allow_access=False)

        result = guard(instance, user=self.regular_user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, PermissionGuard.ERROR_CODE_PERMISSION_DENIED_CUSTOM)

    def test_custom_error_message(self):
        """Test custom error message."""
        custom_message = "You need special access for this"
        guard = PermissionGuard(requires_moderator=True, error_message=custom_message)

        guard(self.instance, user=self.regular_user)

        self.assertEqual(guard.get_error_message(), custom_message)

    def test_get_required_roles_moderator(self):
        """Test get_required_roles for moderator requirement."""
        guard = PermissionGuard(requires_moderator=True)

        roles = guard.get_required_roles()

        self.assertEqual(set(roles), set(MODERATOR_ROLES))

    def test_get_required_roles_admin(self):
        """Test get_required_roles for admin requirement."""
        guard = PermissionGuard(requires_admin=True)

        roles = guard.get_required_roles()

        self.assertEqual(set(roles), set(ADMIN_ROLES))


# ============================================================================
# OwnershipGuard Tests
# ============================================================================


class OwnershipGuardTests(TestCase):
    """Tests for OwnershipGuard class."""

    def setUp(self):
        """Set up test fixtures."""
        self.owner = User.objects.create_user(
            username="owner", email="owner@example.com", password="testpass123", role="USER"
        )
        self.other_user = User.objects.create_user(
            username="other", email="other@example.com", password="testpass123", role="USER"
        )
        self.moderator = User.objects.create_user(
            username="moderator", email="moderator@example.com", password="testpass123", role="MODERATOR"
        )
        self.admin = User.objects.create_user(
            username="admin", email="admin@example.com", password="testpass123", role="ADMIN"
        )

    def test_no_user_fails(self):
        """Test that guard fails when no user is provided."""
        instance = MockInstance(created_by=self.owner)
        guard = OwnershipGuard()

        result = guard(instance, user=None)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, OwnershipGuard.ERROR_CODE_NO_USER)

    def test_owner_passes_created_by(self):
        """Test that owner passes via created_by field."""
        instance = MockInstance(created_by=self.owner)
        guard = OwnershipGuard()

        result = guard(instance, user=self.owner)

        self.assertTrue(result)

    def test_owner_passes_user_field(self):
        """Test that owner passes via user field."""
        instance = MockInstance(user=self.owner)
        guard = OwnershipGuard()

        result = guard(instance, user=self.owner)

        self.assertTrue(result)

    def test_owner_passes_submitted_by(self):
        """Test that owner passes via submitted_by field."""
        instance = MockInstance(submitted_by=self.owner)
        guard = OwnershipGuard()

        result = guard(instance, user=self.owner)

        self.assertTrue(result)

    def test_non_owner_fails(self):
        """Test that non-owner fails."""
        instance = MockInstance(created_by=self.owner)
        guard = OwnershipGuard()

        result = guard(instance, user=self.other_user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, OwnershipGuard.ERROR_CODE_NOT_OWNER)

    def test_moderator_override(self):
        """Test that moderator can bypass ownership check."""
        instance = MockInstance(created_by=self.owner)
        guard = OwnershipGuard(allow_moderator_override=True)

        result = guard(instance, user=self.moderator)

        self.assertTrue(result)

    def test_admin_override(self):
        """Test that admin can bypass ownership check."""
        instance = MockInstance(created_by=self.owner)
        guard = OwnershipGuard(allow_admin_override=True)

        result = guard(instance, user=self.admin)

        self.assertTrue(result)

    def test_custom_owner_fields(self):
        """Test custom owner field names."""
        instance = MockInstance(author=self.owner)
        guard = OwnershipGuard(owner_fields=["author"])

        result = guard(instance, user=self.owner)

        self.assertTrue(result)

    def test_anonymous_user_fails(self):
        """Test that anonymous user fails ownership check."""
        instance = MockInstance(created_by=self.owner)
        guard = OwnershipGuard()
        anonymous = AnonymousUser()

        result = guard(instance, user=anonymous)

        self.assertFalse(result)


# ============================================================================
# AssignmentGuard Tests
# ============================================================================


class AssignmentGuardTests(TestCase):
    """Tests for AssignmentGuard class."""

    def setUp(self):
        """Set up test fixtures."""
        self.assigned_user = User.objects.create_user(
            username="assigned", email="assigned@example.com", password="testpass123", role="MODERATOR"
        )
        self.other_user = User.objects.create_user(
            username="other", email="other@example.com", password="testpass123", role="MODERATOR"
        )
        self.admin = User.objects.create_user(
            username="admin", email="admin@example.com", password="testpass123", role="ADMIN"
        )

    def test_no_user_fails(self):
        """Test that guard fails when no user is provided."""
        instance = MockInstance(assigned_to=self.assigned_user)
        guard = AssignmentGuard()

        result = guard(instance, user=None)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, AssignmentGuard.ERROR_CODE_NO_USER)

    def test_assigned_user_passes(self):
        """Test that assigned user passes."""
        instance = MockInstance(assigned_to=self.assigned_user)
        guard = AssignmentGuard()

        result = guard(instance, user=self.assigned_user)

        self.assertTrue(result)

    def test_unassigned_user_fails(self):
        """Test that unassigned user fails."""
        instance = MockInstance(assigned_to=self.assigned_user)
        guard = AssignmentGuard()

        result = guard(instance, user=self.other_user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, AssignmentGuard.ERROR_CODE_NOT_ASSIGNED)

    def test_admin_override(self):
        """Test that admin can bypass assignment check."""
        instance = MockInstance(assigned_to=self.assigned_user)
        guard = AssignmentGuard(allow_admin_override=True)

        result = guard(instance, user=self.admin)

        self.assertTrue(result)

    def test_require_assignment_with_no_assignment(self):
        """Test require_assignment fails when no one is assigned."""
        instance = MockInstance(assigned_to=None)
        guard = AssignmentGuard(require_assignment=True)

        result = guard(instance, user=self.assigned_user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, AssignmentGuard.ERROR_CODE_NO_ASSIGNMENT)

    def test_custom_assignment_fields(self):
        """Test custom assignment field names."""
        instance = MockInstance(reviewer=self.assigned_user)
        guard = AssignmentGuard(assignment_fields=["reviewer"])

        result = guard(instance, user=self.assigned_user)

        self.assertTrue(result)

    def test_error_message_for_no_assignment(self):
        """Test error message when no assignment exists."""
        instance = MockInstance(assigned_to=None)
        guard = AssignmentGuard(require_assignment=True)

        guard(instance, user=self.assigned_user)

        self.assertIn("assigned", guard.get_error_message().lower())


# ============================================================================
# StateGuard Tests
# ============================================================================


class StateGuardTests(TestCase):
    """Tests for StateGuard class."""

    def setUp(self):
        """Set up test fixtures."""
        self.user = User.objects.create_user(
            username="user", email="user@example.com", password="testpass123", role="USER"
        )

    def test_allowed_states_passes(self):
        """Test that guard passes when in allowed state."""
        instance = MockInstance(status="PENDING")
        guard = StateGuard(allowed_states=["PENDING", "UNDER_REVIEW"])

        result = guard(instance, user=self.user)

        self.assertTrue(result)

    def test_allowed_states_fails(self):
        """Test that guard fails when not in allowed state."""
        instance = MockInstance(status="COMPLETED")
        guard = StateGuard(allowed_states=["PENDING", "UNDER_REVIEW"])

        result = guard(instance, user=self.user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, StateGuard.ERROR_CODE_INVALID_STATE)

    def test_blocked_states_passes(self):
        """Test that guard passes when not in blocked state."""
        instance = MockInstance(status="PENDING")
        guard = StateGuard(blocked_states=["COMPLETED", "CANCELLED"])

        result = guard(instance, user=self.user)

        self.assertTrue(result)

    def test_blocked_states_fails(self):
        """Test that guard fails when in blocked state."""
        instance = MockInstance(status="COMPLETED")
        guard = StateGuard(blocked_states=["COMPLETED", "CANCELLED"])

        result = guard(instance, user=self.user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, StateGuard.ERROR_CODE_BLOCKED_STATE)

    def test_custom_state_field(self):
        """Test using custom state field name."""
        instance = MockInstance(workflow_status="ACTIVE")
        guard = StateGuard(allowed_states=["ACTIVE"], state_field="workflow_status")

        result = guard(instance, user=self.user)

        self.assertTrue(result)

    def test_error_message_includes_states(self):
        """Test that error message includes allowed states."""
        instance = MockInstance(status="COMPLETED")
        guard = StateGuard(allowed_states=["PENDING", "UNDER_REVIEW"])

        guard(instance, user=self.user)

        message = guard.get_error_message()
        self.assertIn("PENDING", message)
        self.assertIn("UNDER_REVIEW", message)


# ============================================================================
# MetadataGuard Tests
# ============================================================================


class MetadataGuardTests(TestCase):
    """Tests for MetadataGuard class."""

    def setUp(self):
        """Set up test fixtures."""
        self.user = User.objects.create_user(
            username="user", email="user@example.com", password="testpass123", role="USER"
        )

    def test_required_fields_present(self):
        """Test that guard passes when required fields are present."""
        instance = MockInstance(resolution_notes="Fixed", assigned_to="user")
        guard = MetadataGuard(required_fields=["resolution_notes", "assigned_to"])

        result = guard(instance, user=self.user)

        self.assertTrue(result)

    def test_required_field_missing(self):
        """Test that guard fails when required field is missing."""
        instance = MockInstance(resolution_notes="Fixed")
        guard = MetadataGuard(required_fields=["resolution_notes", "assigned_to"])

        result = guard(instance, user=self.user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, MetadataGuard.ERROR_CODE_MISSING_FIELD)

    def test_required_field_none(self):
        """Test that guard fails when required field is None."""
        instance = MockInstance(resolution_notes=None)
        guard = MetadataGuard(required_fields=["resolution_notes"])

        result = guard(instance, user=self.user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, MetadataGuard.ERROR_CODE_MISSING_FIELD)

    def test_empty_string_fails_check_not_empty(self):
        """Test that empty string fails when check_not_empty is True."""
        instance = MockInstance(resolution_notes="   ")
        guard = MetadataGuard(required_fields=["resolution_notes"], check_not_empty=True)

        result = guard(instance, user=self.user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, MetadataGuard.ERROR_CODE_EMPTY_FIELD)

    def test_empty_list_fails_check_not_empty(self):
        """Test that empty list fails when check_not_empty is True."""
        instance = MockInstance(tags=[])
        guard = MetadataGuard(required_fields=["tags"], check_not_empty=True)

        result = guard(instance, user=self.user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, MetadataGuard.ERROR_CODE_EMPTY_FIELD)

    def test_empty_dict_fails_check_not_empty(self):
        """Test that empty dict fails when check_not_empty is True."""
        instance = MockInstance(metadata={})
        guard = MetadataGuard(required_fields=["metadata"], check_not_empty=True)

        result = guard(instance, user=self.user)

        self.assertFalse(result)
        self.assertEqual(guard.error_code, MetadataGuard.ERROR_CODE_EMPTY_FIELD)

    def test_error_message_includes_field_name(self):
        """Test that error message includes the field name."""
        instance = MockInstance(resolution_notes=None)
        guard = MetadataGuard(required_fields=["resolution_notes"])

        guard(instance, user=self.user)

        message = guard.get_error_message()
        self.assertIn("Resolution Notes", message)


# ============================================================================
# CompositeGuard Tests
# ============================================================================


class CompositeGuardTests(TestCase):
    """Tests for CompositeGuard class."""

    def setUp(self):
        """Set up test fixtures."""
        self.owner = User.objects.create_user(
            username="owner", email="owner@example.com", password="testpass123", role="USER"
        )
        self.moderator = User.objects.create_user(
            username="moderator", email="moderator@example.com", password="testpass123", role="MODERATOR"
        )
        self.non_owner_moderator = User.objects.create_user(
            username="non_owner_moderator",
            email="non_owner_moderator@example.com",
            password="testpass123",
            role="MODERATOR",
        )

    def test_and_operator_all_pass(self):
        """Test AND operator when all guards pass."""
        instance = MockInstance(created_by=self.moderator)
        guards = [PermissionGuard(requires_moderator=True), OwnershipGuard()]
        composite = CompositeGuard(guards, operator="AND")

        result = composite(instance, user=self.moderator)

        self.assertTrue(result)

    def test_and_operator_one_fails(self):
        """Test AND operator when one guard fails."""
        instance = MockInstance(created_by=self.owner)
        guards = [
            PermissionGuard(requires_moderator=True),  # Will pass for moderator
            OwnershipGuard(),  # Will fail - moderator is not owner
        ]
        composite = CompositeGuard(guards, operator="AND")

        result = composite(instance, user=self.non_owner_moderator)

        self.assertFalse(result)
        self.assertEqual(composite.error_code, CompositeGuard.ERROR_CODE_SOME_FAILED)

    def test_or_operator_one_passes(self):
        """Test OR operator when one guard passes."""
        instance = MockInstance(created_by=self.owner)
        guards = [
            PermissionGuard(requires_moderator=True),  # Will fail for owner
            OwnershipGuard(),  # Will pass - user is owner
        ]
        composite = CompositeGuard(guards, operator="OR")

        result = composite(instance, user=self.owner)

        self.assertTrue(result)

    def test_or_operator_all_fail(self):
        """Test OR operator when all guards fail."""
        instance = MockInstance(created_by=self.moderator)
        guards = [PermissionGuard(requires_admin=True), OwnershipGuard()]  # Regular user fails  # Not the owner fails
        composite = CompositeGuard(guards, operator="OR")

        result = composite(instance, user=self.owner)

        self.assertFalse(result)
        self.assertEqual(composite.error_code, CompositeGuard.ERROR_CODE_ALL_FAILED)

    def test_nested_composite_guards(self):
        """Test nested composite guards."""
        instance = MockInstance(created_by=self.moderator, status="PENDING")

        # Inner composite: moderator OR owner
        inner = CompositeGuard([PermissionGuard(requires_moderator=True), OwnershipGuard()], operator="OR")

        # Outer composite: (moderator OR owner) AND valid state
        outer = CompositeGuard([inner, StateGuard(allowed_states=["PENDING"])], operator="AND")

        result = outer(instance, user=self.moderator)

        self.assertTrue(result)

    def test_error_message_from_failed_guard(self):
        """Test that error message comes from first failed guard."""
        instance = MockInstance(created_by=self.owner)
        perm_guard = PermissionGuard(requires_admin=True)
        guards = [perm_guard]
        composite = CompositeGuard(guards, operator="AND")

        composite(instance, user=self.owner)

        message = composite.get_error_message()
        self.assertIn("admin", message.lower())


# ============================================================================
# Guard Factory Function Tests
# ============================================================================


class GuardFactoryTests(TestCase):
    """Tests for guard factory functions."""

    def setUp(self):
        """Set up test fixtures."""
        self.moderator = User.objects.create_user(
            username="moderator", email="moderator@example.com", password="testpass123", role="MODERATOR"
        )

    def test_create_permission_guard_moderator(self):
        """Test create_permission_guard with moderator requirement."""
        metadata = {"requires_moderator": True}
        guard = create_permission_guard(metadata)
        instance = MockInstance()

        result = guard(instance, user=self.moderator)

        self.assertTrue(result)

    def test_create_permission_guard_admin(self):
        """Test create_permission_guard with admin requirement."""
        metadata = {"requires_admin_approval": True}
        guard = create_permission_guard(metadata)

        self.assertTrue(guard.requires_admin)

    def test_create_permission_guard_escalation_level(self):
        """Test create_permission_guard with escalation level."""
        metadata = {"escalation_level": "admin"}
        guard = create_permission_guard(metadata)

        self.assertTrue(guard.requires_admin)

    def test_create_ownership_guard(self):
        """Test create_ownership_guard factory."""
        guard = create_ownership_guard(allow_moderator_override=True)

        self.assertTrue(guard.allow_moderator_override)

    def test_create_assignment_guard(self):
        """Test create_assignment_guard factory."""
        guard = create_assignment_guard(require_assignment=True)

        self.assertTrue(guard.require_assignment)

    def test_create_composite_guard(self):
        """Test create_composite_guard factory."""
        guards = [PermissionGuard(), OwnershipGuard()]
        composite = create_composite_guard(guards, operator="OR")

        self.assertEqual(composite.operator, "OR")
        self.assertEqual(len(composite.guards), 2)


# ============================================================================
# Metadata Extraction Tests
# ============================================================================


class MetadataExtractionTests(TestCase):
    """Tests for extract_guards_from_metadata function."""

    def test_extract_moderator_guard(self):
        """Test extracting guard for moderator requirement."""
        metadata = {"requires_moderator": True}
        guards = extract_guards_from_metadata(metadata)

        self.assertEqual(len(guards), 1)
        self.assertIsInstance(guards[0], PermissionGuard)

    def test_extract_admin_guard(self):
        """Test extracting guard for admin requirement."""
        metadata = {"requires_admin_approval": True}
        guards = extract_guards_from_metadata(metadata)

        self.assertEqual(len(guards), 1)
        self.assertTrue(guards[0].requires_admin)

    def test_extract_assignment_guard(self):
        """Test extracting assignment guard."""
        metadata = {"requires_assignment": True}
        guards = extract_guards_from_metadata(metadata)

        self.assertEqual(len(guards), 1)
        self.assertIsInstance(guards[0], AssignmentGuard)

    def test_extract_multiple_guards(self):
        """Test extracting multiple guards."""
        metadata = {"requires_moderator": True, "requires_assignment": True}
        guards = extract_guards_from_metadata(metadata)

        self.assertEqual(len(guards), 2)

    def test_extract_zero_tolerance_guard(self):
        """Test extracting guard for zero tolerance (superuser required)."""
        metadata = {"zero_tolerance": True}
        guards = extract_guards_from_metadata(metadata)

        self.assertEqual(len(guards), 1)
        self.assertTrue(guards[0].requires_superuser)

    def test_invalid_escalation_level_raises(self):
        """Test that invalid escalation level raises ValueError."""
        metadata = {"escalation_level": "invalid"}

        with self.assertRaises(ValueError):
            extract_guards_from_metadata(metadata)


# ============================================================================
# Metadata Validation Tests
# ============================================================================


class MetadataValidationTests(TestCase):
    """Tests for validate_guard_metadata function."""

    def test_valid_metadata(self):
        """Test that valid metadata passes validation."""
        metadata = {"requires_moderator": True, "escalation_level": "admin", "requires_assignment": False}

        is_valid, errors = validate_guard_metadata(metadata)

        self.assertTrue(is_valid)
        self.assertEqual(len(errors), 0)

    def test_invalid_escalation_level(self):
        """Test that invalid escalation level fails validation."""
        metadata = {"escalation_level": "invalid_level"}

        is_valid, errors = validate_guard_metadata(metadata)

        self.assertFalse(is_valid)
        self.assertTrue(any("escalation_level" in e for e in errors))

    def test_invalid_boolean_field(self):
        """Test that non-boolean value for boolean field fails validation."""
        metadata = {"requires_moderator": "yes"}

        is_valid, errors = validate_guard_metadata(metadata)

        self.assertFalse(is_valid)
        self.assertTrue(any("requires_moderator" in e for e in errors))

    def test_required_permissions_not_list(self):
        """Test that non-list required_permissions fails validation."""
        metadata = {"required_permissions": "app.permission"}

        is_valid, errors = validate_guard_metadata(metadata)

        self.assertFalse(is_valid)
        self.assertTrue(any("required_permissions" in e for e in errors))


# ============================================================================
# Role Helper Function Tests
# ============================================================================


class RoleHelperTests(TestCase):
    """Tests for role helper functions."""

    def setUp(self):
        """Set up test fixtures."""
        self.regular_user = User.objects.create_user(
            username="user", email="user@example.com", password="testpass123", role="USER"
        )
        self.moderator = User.objects.create_user(
            username="moderator", email="moderator@example.com", password="testpass123", role="MODERATOR"
        )
        self.admin = User.objects.create_user(
            username="admin", email="admin@example.com", password="testpass123", role="ADMIN"
        )
        self.superuser = User.objects.create_user(
            username="superuser", email="superuser@example.com", password="testpass123", role="SUPERUSER"
        )

    def test_get_user_role(self):
        """Test get_user_role returns correct role."""
        self.assertEqual(get_user_role(self.regular_user), "USER")
        self.assertEqual(get_user_role(self.moderator), "MODERATOR")
        self.assertEqual(get_user_role(self.admin), "ADMIN")
        self.assertEqual(get_user_role(self.superuser), "SUPERUSER")
        self.assertIsNone(get_user_role(None))

    def test_has_role(self):
        """Test has_role function."""
        self.assertTrue(has_role(self.moderator, ["MODERATOR", "ADMIN"]))
        self.assertFalse(has_role(self.regular_user, ["MODERATOR", "ADMIN"]))

    def test_is_moderator_or_above(self):
        """Test is_moderator_or_above function."""
        self.assertFalse(is_moderator_or_above(self.regular_user))
        self.assertTrue(is_moderator_or_above(self.moderator))
        self.assertTrue(is_moderator_or_above(self.admin))
        self.assertTrue(is_moderator_or_above(self.superuser))

    def test_is_admin_or_above(self):
        """Test is_admin_or_above function."""
        self.assertFalse(is_admin_or_above(self.regular_user))
        self.assertFalse(is_admin_or_above(self.moderator))
        self.assertTrue(is_admin_or_above(self.admin))
        self.assertTrue(is_admin_or_above(self.superuser))

    def test_is_superuser_role(self):
        """Test is_superuser_role function."""
        self.assertFalse(is_superuser_role(self.regular_user))
        self.assertFalse(is_superuser_role(self.moderator))
        self.assertFalse(is_superuser_role(self.admin))
        self.assertTrue(is_superuser_role(self.superuser))

    def test_anonymous_user_has_no_role(self):
        """Test that anonymous user has no role."""
        anonymous = AnonymousUser()

        self.assertFalse(has_role(anonymous, ["USER"]))
        self.assertFalse(is_moderator_or_above(anonymous))
        self.assertFalse(is_admin_or_above(anonymous))
        self.assertFalse(is_superuser_role(anonymous))
