"""
Services for ride status transitions and management.
Following Django styleguide pattern for business logic encapsulation.
"""

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

from apps.core.utils import capture_and_log
from apps.rides.models import Ride


class RideStatusService:
    """Service for managing ride status transitions using FSM."""

    @staticmethod
    def open_ride(*, ride_id: int, user: AbstractBaseUser | None = None) -> Ride:
        """
        Open a ride for operation.

        Args:
            ride_id: ID of ride to open
            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 close_ride_temporarily(*, ride_id: int, user: AbstractBaseUser | 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: AbstractBaseUser | 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 mark_ride_closing(
        *,
        ride_id: int,
        closing_date,
        post_closing_status: str,
        user: AbstractBaseUser | None = None,
    ) -> Ride:
        """
        Mark a ride as closing with a specific date and post-closing status.

        Args:
            ride_id: ID of ride to mark as 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: AbstractBaseUser | 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: AbstractBaseUser | 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, user: AbstractBaseUser | None = None) -> Ride:
        """
        Mark a ride as relocated.

        Args:
            ride_id: ID of ride to relocate
            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.relocate(user=user)
            return ride

    @staticmethod
    def process_closing_rides() -> list[Ride]:
        """
        Process all rides in CLOSING status and transition them to their
        post_closing_status if the closing_date has been reached.

        Returns:
            List of rides that were transitioned

        Note:
            This method should be called by a scheduled task/cron job.
        """
        from django.utils import timezone

        transitioned_rides = []
        closing_rides = Ride.objects.filter(
            status="CLOSING",
            closing_date__lte=timezone.now().date(),
        ).select_for_update()

        for ride in closing_rides:
            try:
                with transaction.atomic():
                    ride.apply_post_closing_status()
                    transitioned_rides.append(ride)
            except Exception as e:
                # Capture error to dashboard but continue processing other rides
                capture_and_log(e, f'Process closing ride {ride.id}', source='service')
                continue

        return transitioned_rides
