# tests/unit/models/database/test_admin_platform.py
"""
Unit tests for AdminPlatform model.

Tests the admin-platform junction table model and its relationships.
"""

import pytest
from sqlalchemy.exc import IntegrityError

from app.modules.tenancy.models import AdminPlatform


@pytest.mark.unit
@pytest.mark.database
@pytest.mark.admin
class TestAdminPlatformModel:
    """Test AdminPlatform model creation and constraints."""

    def test_create_admin_platform_assignment(
        self, db, test_platform_admin, test_platform, test_super_admin
    ):
        """Test creating an admin platform assignment."""
        assignment = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment)
        db.commit()
        db.refresh(assignment)

        assert assignment.id is not None
        assert assignment.user_id == test_platform_admin.id
        assert assignment.platform_id == test_platform.id
        assert assignment.is_active is True
        assert assignment.assigned_by_user_id == test_super_admin.id
        assert assignment.assigned_at is not None

    def test_admin_platform_unique_constraint(
        self, db, test_platform_admin, test_platform, test_super_admin
    ):
        """Test that an admin can only be assigned to a platform once."""
        # Create first assignment
        assignment1 = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment1)
        db.commit()

        # Try to create duplicate assignment
        assignment2 = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment2)

        with pytest.raises(IntegrityError):
            db.commit()

    def test_admin_platform_cascade_delete_user(
        self, db, auth_manager, test_platform, test_super_admin
    ):
        """Test that deleting user cascades to admin platform assignments."""
        from app.modules.tenancy.models import User

        # Create a temporary admin
        temp_admin = User(
            email="temp_admin@example.com",
            username="temp_admin",
            hashed_password=auth_manager.hash_password("temppass"),
            role="platform_admin",
            is_active=True,
        )
        db.add(temp_admin)
        db.flush()

        # Create assignment
        assignment = AdminPlatform(
            user_id=temp_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment)
        db.commit()

        assignment_id = assignment.id

        # Delete user - should cascade to assignment
        db.delete(temp_admin)
        db.commit()

        # Verify assignment is gone
        remaining = db.query(AdminPlatform).filter(AdminPlatform.id == assignment_id).first()
        assert remaining is None

    def test_admin_platform_relationships(
        self, db, test_platform_admin, test_platform, test_super_admin
    ):
        """Test AdminPlatform relationships are loaded correctly."""
        assignment = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment)
        db.commit()
        db.refresh(assignment)

        # Test relationships
        assert assignment.user is not None
        assert assignment.user.id == test_platform_admin.id
        assert assignment.platform is not None
        assert assignment.platform.id == test_platform.id
        assert assignment.assigned_by is not None
        assert assignment.assigned_by.id == test_super_admin.id

    def test_admin_platform_properties(
        self, db, test_platform_admin, test_platform, test_super_admin
    ):
        """Test AdminPlatform computed properties."""
        assignment = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment)
        db.commit()
        db.refresh(assignment)

        # Test properties
        assert assignment.platform_code == test_platform.code
        assert assignment.platform_name == test_platform.name

    def test_admin_platform_repr(
        self, db, test_platform_admin, test_platform, test_super_admin
    ):
        """Test AdminPlatform string representation."""
        assignment = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment)
        db.commit()
        db.refresh(assignment)

        repr_str = repr(assignment)
        assert "AdminPlatform" in repr_str
        assert str(test_platform_admin.id) in repr_str
        assert str(test_platform.id) in repr_str


@pytest.mark.unit
@pytest.mark.database
@pytest.mark.admin
class TestUserAdminMethods:
    """Test User model admin-related methods."""

    def test_is_super_admin_true(self, db, test_super_admin):
        """Test is_super_admin property for super admin."""
        assert test_super_admin.is_super_admin is True

    def test_is_super_admin_false_for_platform_admin(self, db, test_platform_admin):
        """Test is_super_admin property for platform admin."""
        assert test_platform_admin.is_super_admin is False

    def test_is_platform_admin_true(self, db, test_platform_admin):
        """Test is_platform_admin property for platform admin."""
        assert test_platform_admin.is_platform_admin is True

    def test_is_platform_admin_false_for_super_admin(self, db, test_super_admin):
        """Test is_platform_admin property for super admin."""
        assert test_super_admin.is_platform_admin is False

    def test_can_access_platform_super_admin(self, db, test_super_admin, test_platform):
        """Test that super admin can access any platform."""
        assert test_super_admin.can_access_platform(test_platform.id) is True

    def test_can_access_platform_assigned(
        self, db, test_platform_admin, test_platform, test_super_admin
    ):
        """Test that platform admin can access assigned platform."""
        # Create assignment
        assignment = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment)
        db.commit()
        db.refresh(test_platform_admin)

        assert test_platform_admin.can_access_platform(test_platform.id) is True

    def test_can_access_platform_not_assigned(
        self, db, test_platform_admin, test_platform
    ):
        """Test that platform admin cannot access unassigned platform."""
        # No assignment created
        assert test_platform_admin.can_access_platform(test_platform.id) is False

    def test_can_access_platform_inactive_assignment(
        self, db, test_platform_admin, test_platform, test_super_admin
    ):
        """Test that platform admin cannot access platform with inactive assignment."""
        # Create inactive assignment
        assignment = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=False,  # Inactive
            assigned_by_user_id=test_super_admin.id,
        )
        db.add(assignment)
        db.commit()
        db.refresh(test_platform_admin)

        assert test_platform_admin.can_access_platform(test_platform.id) is False

    def test_get_accessible_platform_ids_super_admin(self, db, test_super_admin):
        """Test get_accessible_platform_ids returns None for super admin."""
        result = test_super_admin.get_accessible_platform_ids()
        assert result is None  # None means all platforms

    def test_get_accessible_platform_ids_platform_admin(
        self, db, test_platform_admin, test_platform, another_platform, test_super_admin
    ):
        """Test get_accessible_platform_ids returns correct list for platform admin."""
        # Create assignments for both platforms
        assignment1 = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=test_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        assignment2 = AdminPlatform(
            user_id=test_platform_admin.id,
            platform_id=another_platform.id,
            is_active=True,
            assigned_by_user_id=test_super_admin.id,
        )
        db.add_all([assignment1, assignment2])
        db.commit()
        db.refresh(test_platform_admin)

        result = test_platform_admin.get_accessible_platform_ids()
        assert len(result) == 2
        assert test_platform.id in result
        assert another_platform.id in result

    def test_get_accessible_platform_ids_no_assignments(self, db, test_platform_admin):
        """Test get_accessible_platform_ids returns empty list when no assignments."""
        result = test_platform_admin.get_accessible_platform_ids()
        assert result == []

    def test_get_accessible_platform_ids_store_user(self, db, test_store_user):
        """Test get_accessible_platform_ids returns empty list for non-admin."""
        result = test_store_user.get_accessible_platform_ids()
        assert result == []
