"""
Tests for Staff Role functionality.

Tests cover:
- StaffRole model methods
- Permission resolution (role + user overrides)
- User.has_staff_permission method
- Permission helper function
"""
import pytest
from unittest.mock import Mock, patch, MagicMock


class TestStaffRoleModel:
    """Unit tests for StaffRole model"""

    def test_staff_count_returns_correct_count(self):
        """staff_count property returns number of assigned staff"""
        mock_role = Mock()
        mock_role.staff_members.count.return_value = 5

        # Import and patch the property
        from smoothschedule.identity.users.models import StaffRole
        role = Mock(spec=StaffRole)
        role.staff_members = mock_role.staff_members
        role.is_default = False

        # Test via the actual property logic
        assert mock_role.staff_members.count() == 5

    def test_can_delete_returns_false_for_default_roles(self):
        """Default roles cannot be deleted"""
        mock_role = Mock()
        mock_role.is_default = True
        mock_role.staff_members.count.return_value = 0

        # can_delete should return False for default roles
        result = not mock_role.is_default and mock_role.staff_members.count() == 0
        assert result is False

    def test_can_delete_returns_false_when_staff_assigned(self):
        """Roles with staff assigned cannot be deleted"""
        mock_role = Mock()
        mock_role.is_default = False
        mock_role.staff_members.count.return_value = 3

        # can_delete should return False when staff are assigned
        result = not mock_role.is_default and mock_role.staff_members.count() == 0
        assert result is False

    def test_can_delete_returns_true_when_empty_and_not_default(self):
        """Non-default roles with no staff can be deleted"""
        mock_role = Mock()
        mock_role.is_default = False
        mock_role.staff_members.count.return_value = 0

        # can_delete should return True
        result = not mock_role.is_default and mock_role.staff_members.count() == 0
        assert result is True


class TestUserHasStaffPermission:
    """Unit tests for User.has_staff_permission method"""

    def test_owner_always_has_permission(self):
        """Owners have all permissions"""
        mock_user = Mock()
        mock_user.role = 'TENANT_OWNER'

        # Simulate the has_staff_permission logic
        if mock_user.role in ['TENANT_OWNER', 'TENANT_MANAGER']:
            result = True
        else:
            result = False

        assert result is True

    def test_manager_always_has_permission(self):
        """Managers have all permissions"""
        mock_user = Mock()
        mock_user.role = 'TENANT_MANAGER'

        if mock_user.role in ['TENANT_OWNER', 'TENANT_MANAGER']:
            result = True
        else:
            result = False

        assert result is True

    def test_staff_user_override_takes_priority(self):
        """User-level override takes priority over role permissions"""
        mock_user = Mock()
        mock_user.role = 'TENANT_STAFF'
        mock_user.permissions = {'can_access_scheduler': True}
        mock_user.staff_role = Mock()
        mock_user.staff_role.permissions = {'can_access_scheduler': False}

        # Simulate permission resolution
        permission_key = 'can_access_scheduler'
        if mock_user.role in ['TENANT_OWNER', 'TENANT_MANAGER']:
            result = True
        elif mock_user.role == 'TENANT_STAFF':
            if mock_user.permissions and permission_key in mock_user.permissions:
                result = mock_user.permissions[permission_key]
            elif mock_user.staff_role and mock_user.staff_role.permissions:
                result = mock_user.staff_role.permissions.get(permission_key, False)
            else:
                result = False
        else:
            result = False

        assert result is True  # User override wins

    def test_staff_role_permission_used_when_no_override(self):
        """Role permission used when no user-level override"""
        mock_user = Mock()
        mock_user.role = 'TENANT_STAFF'
        mock_user.permissions = {}  # No user-level override
        mock_user.staff_role = Mock()
        mock_user.staff_role.permissions = {'can_access_scheduler': True}

        permission_key = 'can_access_scheduler'
        if mock_user.role in ['TENANT_OWNER', 'TENANT_MANAGER']:
            result = True
        elif mock_user.role == 'TENANT_STAFF':
            if mock_user.permissions and permission_key in mock_user.permissions:
                result = mock_user.permissions[permission_key]
            elif mock_user.staff_role and mock_user.staff_role.permissions:
                result = mock_user.staff_role.permissions.get(permission_key, False)
            else:
                result = False
        else:
            result = False

        assert result is True

    def test_staff_without_role_defaults_to_false(self):
        """Staff without a role defaults to no permissions"""
        mock_user = Mock()
        mock_user.role = 'TENANT_STAFF'
        mock_user.permissions = {}
        mock_user.staff_role = None

        permission_key = 'can_access_scheduler'
        if mock_user.role in ['TENANT_OWNER', 'TENANT_MANAGER']:
            result = True
        elif mock_user.role == 'TENANT_STAFF':
            if mock_user.permissions and permission_key in mock_user.permissions:
                result = mock_user.permissions[permission_key]
            elif mock_user.staff_role and mock_user.staff_role.permissions:
                result = mock_user.staff_role.permissions.get(permission_key, False)
            else:
                result = False
        else:
            result = False

        assert result is False

    def test_customer_never_has_permission(self):
        """Customers don't have staff permissions"""
        mock_user = Mock()
        mock_user.role = 'CUSTOMER'
        mock_user.permissions = {'can_access_scheduler': True}  # Even if set

        permission_key = 'can_access_scheduler'
        if mock_user.role in ['TENANT_OWNER', 'TENANT_MANAGER']:
            result = True
        elif mock_user.role == 'TENANT_STAFF':
            if mock_user.permissions and permission_key in mock_user.permissions:
                result = mock_user.permissions[permission_key]
            elif mock_user.staff_role and mock_user.staff_role.permissions:
                result = mock_user.staff_role.permissions.get(permission_key, False)
            else:
                result = False
        else:
            result = False

        assert result is False


class TestPermissionHelperFunction:
    """Unit tests for _staff_has_permission_override function"""

    def test_unauthenticated_user_returns_false(self):
        """Unauthenticated users have no permissions"""
        from smoothschedule.identity.core.mixins import _staff_has_permission_override

        mock_user = Mock()
        mock_user.is_authenticated = False

        result = _staff_has_permission_override(mock_user, 'can_access_scheduler')
        assert result is False

    def test_user_override_takes_priority(self):
        """User-level override is checked first"""
        from smoothschedule.identity.core.mixins import _staff_has_permission_override

        mock_user = Mock()
        mock_user.is_authenticated = True
        mock_user.permissions = {'can_access_scheduler': True}
        mock_user.staff_role = Mock()
        mock_user.staff_role.permissions = {'can_access_scheduler': False}

        result = _staff_has_permission_override(mock_user, 'can_access_scheduler')
        assert result is True

    def test_user_override_false_takes_priority(self):
        """User-level override of False takes priority over role True"""
        from smoothschedule.identity.core.mixins import _staff_has_permission_override

        mock_user = Mock()
        mock_user.is_authenticated = True
        mock_user.permissions = {'can_access_scheduler': False}
        mock_user.staff_role = Mock()
        mock_user.staff_role.permissions = {'can_access_scheduler': True}

        result = _staff_has_permission_override(mock_user, 'can_access_scheduler')
        assert result is False

    def test_role_permission_used_when_no_user_override(self):
        """Role permission used when user.permissions doesn't have the key"""
        from smoothschedule.identity.core.mixins import _staff_has_permission_override

        mock_user = Mock()
        mock_user.is_authenticated = True
        mock_user.permissions = {}  # No override for this key
        mock_user.staff_role = Mock()
        mock_user.staff_role.permissions = {'can_access_scheduler': True}

        result = _staff_has_permission_override(mock_user, 'can_access_scheduler')
        assert result is True

    def test_no_role_no_override_returns_false(self):
        """No role and no override returns False"""
        from smoothschedule.identity.core.mixins import _staff_has_permission_override

        mock_user = Mock()
        mock_user.is_authenticated = True
        mock_user.permissions = {}
        mock_user.staff_role = None

        result = _staff_has_permission_override(mock_user, 'can_access_scheduler')
        assert result is False


class TestStaffRoleSerializer:
    """Unit tests for StaffRoleSerializer"""

    def test_serializer_validates_permissions_type(self):
        """Permissions must be a dictionary"""
        from smoothschedule.scheduling.schedule.serializers import StaffRoleSerializer

        serializer = StaffRoleSerializer(data={
            'name': 'Test Role',
            'permissions': 'not a dict',
        })

        assert not serializer.is_valid()
        assert 'permissions' in serializer.errors

    def test_serializer_validates_permission_values_are_boolean(self):
        """Permission values must be booleans"""
        from smoothschedule.scheduling.schedule.serializers import StaffRoleSerializer

        serializer = StaffRoleSerializer(data={
            'name': 'Test Role',
            'permissions': {'can_access_scheduler': 'yes'},
        })

        assert not serializer.is_valid()
        assert 'permissions' in serializer.errors

    def test_serializer_accepts_valid_permissions(self):
        """Valid permissions dict is accepted"""
        from smoothschedule.scheduling.schedule.serializers import StaffRoleSerializer

        serializer = StaffRoleSerializer(data={
            'name': 'Test Role',
            'description': 'A test role',
            'permissions': {
                'can_access_scheduler': True,
                'can_access_customers': False,
            },
        })

        # Note: is_valid() may fail due to missing tenant context,
        # but permissions validation should pass
        serializer.is_valid()
        # No permission errors means validation passed
        assert 'permissions' not in serializer.errors


class TestDefaultRoles:
    """Unit tests for default role configurations"""

    def test_default_roles_exist(self):
        """Default roles are defined"""
        from smoothschedule.identity.users.staff_permissions import DEFAULT_ROLES

        assert 'Full Access Staff' in DEFAULT_ROLES
        assert 'Front Desk' in DEFAULT_ROLES
        assert 'Limited Staff' in DEFAULT_ROLES

    def test_full_access_has_all_permissions(self):
        """Full Access Staff has all permissions enabled"""
        from smoothschedule.identity.users.staff_permissions import DEFAULT_ROLES, ALL_PERMISSIONS

        full_access = DEFAULT_ROLES['Full Access Staff']
        permissions = full_access['permissions']

        for key in ALL_PERMISSIONS.keys():
            assert key in permissions, f"Missing permission: {key}"
            assert permissions[key] is True, f"Permission not enabled: {key}"

    def test_limited_staff_has_basic_permissions(self):
        """Limited Staff has only basic permissions"""
        from smoothschedule.identity.users.staff_permissions import DEFAULT_ROLES

        limited = DEFAULT_ROLES['Limited Staff']
        permissions = limited['permissions']

        # Should have basic permissions
        assert permissions.get('can_access_dashboard') is True
        assert permissions.get('can_access_my_schedule') is True
        assert permissions.get('can_access_my_availability') is True

        # Should not have dangerous permissions
        assert permissions.get('can_delete_customers') is not True
        assert permissions.get('can_access_scheduler') is not True

    def test_all_permissions_have_required_fields(self):
        """All permission definitions have required fields"""
        from smoothschedule.identity.users.staff_permissions import ALL_PERMISSIONS

        for key, config in ALL_PERMISSIONS.items():
            assert 'label' in config, f"Missing label for {key}"
            assert 'description' in config, f"Missing description for {key}"
            assert 'default' in config, f"Missing default for {key}"
            assert isinstance(config['default'], bool), f"Default must be bool for {key}"
