"""
Test fixtures for state machine tests.

This module provides reusable fixtures for creating test data:
- User factories for different roles
- Model instance factories for moderation, parks, rides
- Mock objects for testing guards and callbacks
"""

from typing import Any

from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType

User = get_user_model()


class UserFactory:
    """Factory for creating users with different roles."""

    _counter = 0

    @classmethod
    def _get_unique_id(cls) -> int:
        """Get a unique counter for creating unique usernames."""
        cls._counter += 1
        return cls._counter

    @classmethod
    def create_user(
        cls,
        role: str = "USER",
        username: str | None = None,
        email: str | None = None,
        password: str = "testpass123",
        **kwargs,
    ) -> User:
        """
        Create a user with specified role.

        Args:
            role: User role (USER, MODERATOR, ADMIN, SUPERUSER)
            username: Username (auto-generated if not provided)
            email: Email (auto-generated if not provided)
            password: Password for the user
            **kwargs: Additional user fields

        Returns:
            Created User instance
        """
        uid = cls._get_unique_id()
        if username is None:
            username = f"user_{role.lower()}_{uid}"
        if email is None:
            email = f"{role.lower()}_{uid}@example.com"

        return User.objects.create_user(username=username, email=email, password=password, role=role, **kwargs)

    @classmethod
    def create_regular_user(cls, **kwargs) -> User:
        """Create a regular user."""
        return cls.create_user(role="USER", **kwargs)

    @classmethod
    def create_moderator(cls, **kwargs) -> User:
        """Create a moderator user."""
        return cls.create_user(role="MODERATOR", **kwargs)

    @classmethod
    def create_admin(cls, **kwargs) -> User:
        """Create an admin user."""
        return cls.create_user(role="ADMIN", **kwargs)

    @classmethod
    def create_superuser(cls, **kwargs) -> User:
        """Create a superuser."""
        return cls.create_user(role="SUPERUSER", **kwargs)


class CompanyFactory:
    """Factory for creating company instances."""

    _counter = 0

    @classmethod
    def _get_unique_id(cls) -> int:
        cls._counter += 1
        return cls._counter

    @classmethod
    def create_operator(cls, name: str | None = None, **kwargs) -> Any:
        """Create an operator company."""
        from apps.parks.models import Company

        uid = cls._get_unique_id()
        if name is None:
            name = f"Test Operator {uid}"

        defaults = {"name": name, "description": f"Test operator company {uid}", "roles": ["OPERATOR"]}
        defaults.update(kwargs)
        return Company.objects.create(**defaults)

    @classmethod
    def create_manufacturer(cls, name: str | None = None, **kwargs) -> Any:
        """Create a manufacturer company."""
        from apps.rides.models import Company

        uid = cls._get_unique_id()
        if name is None:
            name = f"Test Manufacturer {uid}"

        defaults = {"name": name, "description": f"Test manufacturer company {uid}", "roles": ["MANUFACTURER"]}
        defaults.update(kwargs)
        return Company.objects.create(**defaults)


class ParkFactory:
    """Factory for creating park instances."""

    _counter = 0

    @classmethod
    def _get_unique_id(cls) -> int:
        cls._counter += 1
        return cls._counter

    @classmethod
    def create_park(
        cls, name: str | None = None, operator: Any | None = None, status: str = "OPERATING", **kwargs
    ) -> Any:
        """
        Create a park with specified status.

        Args:
            name: Park name (auto-generated if not provided)
            operator: Operator company (auto-created if not provided)
            status: Park status
            **kwargs: Additional park fields

        Returns:
            Created Park instance
        """
        from apps.parks.models import Park

        uid = cls._get_unique_id()
        if name is None:
            name = f"Test Park {uid}"
        if operator is None:
            operator = CompanyFactory.create_operator()

        defaults = {
            "name": name,
            "slug": f"test-park-{uid}",
            "description": f"A test park {uid}",
            "operator": operator,
            "status": status,
            "timezone": "America/New_York",
        }
        defaults.update(kwargs)
        return Park.objects.create(**defaults)


class RideFactory:
    """Factory for creating ride instances."""

    _counter = 0

    @classmethod
    def _get_unique_id(cls) -> int:
        cls._counter += 1
        return cls._counter

    @classmethod
    def create_ride(
        cls,
        name: str | None = None,
        park: Any | None = None,
        manufacturer: Any | None = None,
        status: str = "OPERATING",
        **kwargs,
    ) -> Any:
        """
        Create a ride with specified status.

        Args:
            name: Ride name (auto-generated if not provided)
            park: Park for the ride (auto-created if not provided)
            manufacturer: Manufacturer company (auto-created if not provided)
            status: Ride status
            **kwargs: Additional ride fields

        Returns:
            Created Ride instance
        """
        from apps.rides.models import Ride

        uid = cls._get_unique_id()
        if name is None:
            name = f"Test Ride {uid}"
        if park is None:
            park = ParkFactory.create_park()
        if manufacturer is None:
            manufacturer = CompanyFactory.create_manufacturer()

        defaults = {
            "name": name,
            "slug": f"test-ride-{uid}",
            "description": f"A test ride {uid}",
            "park": park,
            "manufacturer": manufacturer,
            "status": status,
        }
        defaults.update(kwargs)
        return Ride.objects.create(**defaults)


class EditSubmissionFactory:
    """Factory for creating edit submission instances."""

    _counter = 0

    @classmethod
    def _get_unique_id(cls) -> int:
        cls._counter += 1
        return cls._counter

    @classmethod
    def create_submission(
        cls,
        user: Any | None = None,
        target_object: Any | None = None,
        status: str = "PENDING",
        changes: dict[str, Any] | None = None,
        **kwargs,
    ) -> Any:
        """
        Create an edit submission.

        Args:
            user: User who submitted (auto-created if not provided)
            target_object: Object being edited (auto-created if not provided)
            status: Submission status
            changes: Changes dictionary
            **kwargs: Additional fields

        Returns:
            Created EditSubmission instance
        """
        from apps.moderation.models import EditSubmission
        from apps.parks.models import Company

        uid = cls._get_unique_id()
        if user is None:
            user = UserFactory.create_regular_user()
        if target_object is None:
            target_object = Company.objects.create(name=f"Target Company {uid}", description="Test company")
        if changes is None:
            changes = {"name": f"Updated Name {uid}"}

        content_type = ContentType.objects.get_for_model(target_object)

        defaults = {
            "user": user,
            "content_type": content_type,
            "object_id": target_object.id,
            "submission_type": "EDIT",
            "changes": changes,
            "status": status,
            "reason": f"Test reason {uid}",
        }
        defaults.update(kwargs)
        return EditSubmission.objects.create(**defaults)


class ModerationReportFactory:
    """Factory for creating moderation report instances."""

    _counter = 0

    @classmethod
    def _get_unique_id(cls) -> int:
        cls._counter += 1
        return cls._counter

    @classmethod
    def create_report(
        cls, reporter: Any | None = None, target_object: Any | None = None, status: str = "PENDING", **kwargs
    ) -> Any:
        """
        Create a moderation report.

        Args:
            reporter: User who reported (auto-created if not provided)
            target_object: Object being reported (auto-created if not provided)
            status: Report status
            **kwargs: Additional fields

        Returns:
            Created ModerationReport instance
        """
        from apps.moderation.models import ModerationReport
        from apps.parks.models import Company

        uid = cls._get_unique_id()
        if reporter is None:
            reporter = UserFactory.create_regular_user()
        if target_object is None:
            target_object = Company.objects.create(name=f"Reported Company {uid}", description="Test company")

        content_type = ContentType.objects.get_for_model(target_object)

        defaults = {
            "report_type": "CONTENT",
            "status": status,
            "priority": "MEDIUM",
            "reported_entity_type": target_object._meta.model_name,
            "reported_entity_id": target_object.id,
            "content_type": content_type,
            "reason": f"Test reason {uid}",
            "description": f"Test report description {uid}",
            "reported_by": reporter,
        }
        defaults.update(kwargs)
        return ModerationReport.objects.create(**defaults)


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

    Example:
        instance = MockInstance(
            status='PENDING',
            created_by=user,
            assigned_to=moderator
        )
    """

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

    def __repr__(self):
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"MockInstance({attrs})"
