"""
Services for ride-related business logic.
Following Django styleguide pattern for business logic encapsulation.
"""

from typing import Any

from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractBaseUser
from django.db import transaction

from apps.rides.models import Ride

# Use AbstractBaseUser for type hinting
UserType = AbstractBaseUser
User = get_user_model()


class RideService:
    """Service for managing ride operations."""

    @staticmethod
    def create_ride(
        *,
        name: str,
        park_id: int,
        description: str = "",
        status: str = "OPERATING",
        category: str = "",
        manufacturer_id: int | None = None,
        designer_id: int | None = None,
        ride_model_id: int | None = None,
        park_area_id: int | None = None,
        opening_date: str | None = None,
        closing_date: str | None = None,
        created_by: UserType | None = None,
    ) -> Ride:
        """
        Create a new ride with validation.

        Args:
            name: Ride name
            park_id: ID of the park
            description: Ride description
            status: Operating status
            category: Ride category
            manufacturer_id: ID of manufacturer company
            designer_id: ID of designer company
            ride_model_id: ID of ride model
            park_area_id: ID of park area
            opening_date: Opening date
            closing_date: Closing date
            created_by: User creating the ride

        Returns:
            Created Ride instance

        Raises:
            ValidationError: If ride data is invalid
        """
        with transaction.atomic():
            from apps.parks.models import Park

            # Get park
            park = Park.objects.get(id=park_id)

            # Create ride instance
            ride = Ride(
                name=name,
                park=park,
                description=description,
                status=status,
                category=category,
                opening_date=opening_date,
                closing_date=closing_date,
            )

            # Set foreign key relationships if provided
            if park_area_id:
                from apps.parks.models import ParkArea

                ride.park_area = ParkArea.objects.get(id=park_area_id)

            if manufacturer_id:
                from apps.rides.models import Company

                ride.manufacturer = Company.objects.get(id=manufacturer_id)

            if designer_id:
                from apps.rides.models import Company

                ride.designer = Company.objects.get(id=designer_id)

            if ride_model_id:
                from apps.rides.models import RideModel

                ride.ride_model = RideModel.objects.get(id=ride_model_id)

            # CRITICAL STYLEGUIDE FIX: Call full_clean before save
            ride.full_clean()
            ride.save()

            return ride

    @staticmethod
    def update_ride(
        *,
        ride_id: int,
        updates: dict[str, Any],
        updated_by: UserType | None = None,
    ) -> Ride:
        """
        Update an existing ride with validation.

        Args:
            ride_id: ID of ride to update
            updates: Dictionary of field updates
            updated_by: User performing the update

        Returns:
            Updated Ride instance

        Raises:
            Ride.DoesNotExist: If ride doesn't exist
            ValidationError: If update data is invalid
        """
        with transaction.atomic():
            ride = Ride.objects.select_for_update().get(id=ride_id)

            # Apply updates
            for field, value in updates.items():
                if hasattr(ride, field):
                    setattr(ride, field, value)

            # CRITICAL STYLEGUIDE FIX: Call full_clean before save
            ride.full_clean()
            ride.save()

            return ride

    @staticmethod
    def close_ride_temporarily(*, ride_id: int, user: UserType | None = None) -> Ride:
        """
        Temporarily close a ride.

        Args:
            ride_id: ID of ride to close temporarily
            user: User performing the action

        Returns:
            Updated Ride instance

        Raises:
            Ride.DoesNotExist: If ride doesn't exist
        """
        with transaction.atomic():
            ride = Ride.objects.select_for_update().get(id=ride_id)
            ride.close_temporarily(user=user)
            return ride

    @staticmethod
    def mark_ride_sbno(*, ride_id: int, user: UserType | None = None) -> Ride:
        """
        Mark a ride as SBNO (Standing But Not Operating).

        Args:
            ride_id: ID of ride to mark as SBNO
            user: User performing the action

        Returns:
            Updated Ride instance

        Raises:
            Ride.DoesNotExist: If ride doesn't exist
        """
        with transaction.atomic():
            ride = Ride.objects.select_for_update().get(id=ride_id)
            ride.mark_sbno(user=user)
            return ride

    @staticmethod
    def schedule_ride_closing(
        *,
        ride_id: int,
        closing_date,
        post_closing_status: str,
        user: UserType | None = None,
    ) -> Ride:
        """
        Schedule a ride to close on a specific date with a post-closing status.

        Args:
            ride_id: ID of ride to schedule for closing
            closing_date: Date when ride will close
            post_closing_status: Status to transition to after closing
            user: User performing the action

        Returns:
            Updated Ride instance

        Raises:
            Ride.DoesNotExist: If ride doesn't exist
            ValidationError: If post_closing_status is not set
        """
        with transaction.atomic():
            ride = Ride.objects.select_for_update().get(id=ride_id)
            ride.mark_closing(
                closing_date=closing_date,
                post_closing_status=post_closing_status,
                user=user,
            )
            return ride

    @staticmethod
    def close_ride_permanently(*, ride_id: int, user: UserType | None = None) -> Ride:
        """
        Permanently close a ride.

        Args:
            ride_id: ID of ride to close permanently
            user: User performing the action

        Returns:
            Updated Ride instance

        Raises:
            Ride.DoesNotExist: If ride doesn't exist
        """
        with transaction.atomic():
            ride = Ride.objects.select_for_update().get(id=ride_id)
            ride.close_permanently(user=user)
            return ride

    @staticmethod
    def demolish_ride(*, ride_id: int, user: UserType | None = None) -> Ride:
        """
        Mark a ride as demolished.

        Args:
            ride_id: ID of ride to demolish
            user: User performing the action

        Returns:
            Updated Ride instance

        Raises:
            Ride.DoesNotExist: If ride doesn't exist
        """
        with transaction.atomic():
            ride = Ride.objects.select_for_update().get(id=ride_id)
            ride.demolish(user=user)
            return ride

    @staticmethod
    def relocate_ride(*, ride_id: int, new_park_id: int, user: UserType | None = None) -> Ride:
        """
        Relocate a ride to a new park.

        Args:
            ride_id: ID of ride to relocate
            new_park_id: ID of the new park
            user: User performing the action

        Returns:
            Updated Ride instance

        Raises:
            Ride.DoesNotExist: If ride doesn't exist
        """
        with transaction.atomic():
            from apps.parks.models import Park

            ride = Ride.objects.select_for_update().get(id=ride_id)
            new_park = Park.objects.get(id=new_park_id)

            # Mark as relocated first
            ride.relocate(user=user)

            # Move to new park
            ride.move_to_park(new_park, clear_park_area=True)

            return ride

    @staticmethod
    def reopen_ride(*, ride_id: int, user: UserType | None = None) -> Ride:
        """
        Reopen a ride for operation.

        Args:
            ride_id: ID of ride to reopen
            user: User performing the action

        Returns:
            Updated Ride instance

        Raises:
            Ride.DoesNotExist: If ride doesn't exist
        """
        with transaction.atomic():
            ride = Ride.objects.select_for_update().get(id=ride_id)
            ride.open(user=user)
            return ride

    @staticmethod
    def handle_new_entity_suggestions(
        *,
        form_data: dict[str, Any],
        submitter: UserType,
    ) -> dict[str, Any]:
        """
        Handle suggestions for new manufacturers, designers, and ride models.

        Creates moderation submissions for entities that don't exist in the system.
        This extracts the business logic from RideCreateView and RideUpdateView.

        Args:
            form_data: Cleaned form data containing search fields and selections
            submitter: User making the suggestions

        Returns:
            Dictionary with lists of created submission IDs by type:
            {
                'manufacturers': [...],
                'designers': [...],
                'ride_models': [...],
                'total_submissions': int
            }
        """
        from apps.moderation.services import ModerationService

        result = {"manufacturers": [], "designers": [], "ride_models": [], "total_submissions": 0}

        # Check for new manufacturer
        manufacturer_name = form_data.get("manufacturer_search")
        if manufacturer_name and not form_data.get("manufacturer"):
            submission = ModerationService.create_edit_submission_with_queue(
                content_object=None,
                changes={"name": manufacturer_name, "roles": ["MANUFACTURER"]},
                submitter=submitter,
                submission_type="CREATE",
                reason=f"New manufacturer suggested: {manufacturer_name}",
            )
            if submission:
                result["manufacturers"].append(submission.id)
                result["total_submissions"] += 1

        # Check for new designer
        designer_name = form_data.get("designer_search")
        if designer_name and not form_data.get("designer"):
            submission = ModerationService.create_edit_submission_with_queue(
                content_object=None,
                changes={"name": designer_name, "roles": ["DESIGNER"]},
                submitter=submitter,
                submission_type="CREATE",
                reason=f"New designer suggested: {designer_name}",
            )
            if submission:
                result["designers"].append(submission.id)
                result["total_submissions"] += 1

        # Check for new ride model
        ride_model_name = form_data.get("ride_model_search")
        manufacturer = form_data.get("manufacturer")
        if ride_model_name and not form_data.get("ride_model") and manufacturer:
            submission = ModerationService.create_edit_submission_with_queue(
                content_object=None,
                changes={
                    "name": ride_model_name,
                    "manufacturer": manufacturer.id,
                },
                submitter=submitter,
                submission_type="CREATE",
                reason=f"New ride model suggested: {ride_model_name}",
            )
            if submission:
                result["ride_models"].append(submission.id)
                result["total_submissions"] += 1

        return result
