"""
Integration tests for FSM (Finite State Machine) transition workflows.

These tests verify the complete state transition workflows for
Parks and Rides using the FSM implementation.
"""

from datetime import date, timedelta

import pytest
from django.test import TestCase
from django_fsm import TransitionNotAllowed

from tests.factories import (
    ParkAreaFactory,
    ParkFactory,
    RideFactory,
    UserFactory,
)


@pytest.mark.django_db
class TestParkFSMTransitions(TestCase):
    """Integration tests for Park FSM transitions."""

    def test__park_operating_to_closed_temp__transition_succeeds(self):
        """Test transitioning operating park to temporarily closed."""
        park = ParkFactory(status="OPERATING")
        user = UserFactory()

        park.close_temporarily(user=user)

        assert park.status == "CLOSED_TEMP"

    def test__park_closed_temp_to_operating__transition_succeeds(self):
        """Test reopening temporarily closed park."""
        park = ParkFactory(status="CLOSED_TEMP")
        user = UserFactory()

        park.open(user=user)

        assert park.status == "OPERATING"

    def test__park_operating_to_closed_perm__transition_succeeds(self):
        """Test closing operating park permanently."""
        park = ParkFactory(status="OPERATING")
        user = UserFactory()

        park.close_permanently(user=user)

        assert park.status == "CLOSED_PERM"

    def test__park_closed_perm_to_operating__transition_not_allowed(self):
        """Test permanently closed park cannot reopen."""
        park = ParkFactory(status="CLOSED_PERM")
        user = UserFactory()

        # This should fail - can't reopen permanently closed park
        with pytest.raises((TransitionNotAllowed, ValueError)):
            park.open(user=user)


@pytest.mark.django_db
class TestRideFSMTransitions(TestCase):
    """Integration tests for Ride FSM transitions."""

    def test__ride_operating_to_closed_temp__transition_succeeds(self):
        """Test transitioning operating ride to temporarily closed."""
        ride = RideFactory(status="OPERATING")
        user = UserFactory()

        ride.close_temporarily(user=user)

        assert ride.status == "CLOSED_TEMP"

    def test__ride_closed_temp_to_operating__transition_succeeds(self):
        """Test reopening temporarily closed ride."""
        ride = RideFactory(status="CLOSED_TEMP")
        user = UserFactory()

        ride.open(user=user)

        assert ride.status == "OPERATING"

    def test__ride_operating_to_sbno__transition_succeeds(self):
        """Test transitioning operating ride to SBNO (Standing But Not Operating)."""
        ride = RideFactory(status="OPERATING")
        user = UserFactory()

        ride.mark_sbno(user=user)

        assert ride.status == "SBNO"

    def test__ride_sbno_to_operating__transition_succeeds(self):
        """Test reopening SBNO ride."""
        ride = RideFactory(status="SBNO")
        user = UserFactory()

        ride.open(user=user)

        assert ride.status == "OPERATING"

    def test__ride_operating_to_closing__with_date__transition_succeeds(self):
        """Test scheduling ride for closing."""
        ride = RideFactory(status="OPERATING")
        user = UserFactory()
        closing_date = date.today() + timedelta(days=30)

        ride.mark_closing(
            closing_date=closing_date,
            post_closing_status="DEMOLISHED",
            user=user,
        )

        assert ride.status == "CLOSING"
        assert ride.closing_date == closing_date
        assert ride.post_closing_status == "DEMOLISHED"

    def test__ride_closing_to_demolished__transition_succeeds(self):
        """Test transitioning closing ride to demolished."""
        ride = RideFactory(status="CLOSING")
        ride.post_closing_status = "DEMOLISHED"
        ride.save()
        user = UserFactory()

        ride.demolish(user=user)

        assert ride.status == "DEMOLISHED"

    def test__ride_operating_to_relocated__transition_succeeds(self):
        """Test marking ride as relocated."""
        ride = RideFactory(status="OPERATING")
        user = UserFactory()

        ride.relocate(user=user)

        assert ride.status == "RELOCATED"


@pytest.mark.django_db
class TestRideRelocationWorkflow(TestCase):
    """Integration tests for ride relocation workflow."""

    def test__relocate_ride__to_new_park__updates_park(self):
        """Test relocating ride to new park updates the park relationship."""
        old_park = ParkFactory(name="Old Park")
        new_park = ParkFactory(name="New Park")
        ride = RideFactory(park=old_park, status="OPERATING")
        user = UserFactory()

        # Mark as relocated first
        ride.relocate(user=user)
        assert ride.status == "RELOCATED"

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

        assert ride.park == new_park
        assert ride.park_area is None  # Cleared during relocation

    def test__relocate_ride__clears_park_area(self):
        """Test relocating ride clears park area."""
        park = ParkFactory()
        area = ParkAreaFactory(park=park)
        new_park = ParkFactory()

        ride = RideFactory(park=park, park_area=area, status="OPERATING")
        user = UserFactory()

        ride.relocate(user=user)
        ride.move_to_park(new_park, clear_park_area=True)

        assert ride.park_area is None


@pytest.mark.django_db
class TestRideStatusTransitionHistory(TestCase):
    """Integration tests for ride status transition history."""

    def test__multiple_transitions__records_status_since(self):
        """Test multiple transitions update status_since correctly."""
        ride = RideFactory(status="OPERATING")
        user = UserFactory()

        # First transition
        ride.close_temporarily(user=user)
        first_status_since = ride.status_since

        assert ride.status == "CLOSED_TEMP"

        # Second transition
        ride.open(user=user)
        second_status_since = ride.status_since

        assert ride.status == "OPERATING"
        # status_since should be updated for new transition
        assert second_status_since >= first_status_since


@pytest.mark.django_db
class TestParkRideCascadeStatus(TestCase):
    """Integration tests for park status affecting rides."""

    def test__close_park__does_not_auto_close_rides(self):
        """Test closing park doesn't automatically close rides."""
        park = ParkFactory(status="OPERATING")
        ride = RideFactory(park=park, status="OPERATING")
        user = UserFactory()

        # Close the park
        park.close_temporarily(user=user)

        # Ride should still be operating (business decision)
        ride.refresh_from_db()
        assert ride.status == "OPERATING"  # Rides keep their independent status

    def test__reopen_park__allows_ride_operation(self):
        """Test reopening park allows rides to continue operating."""
        park = ParkFactory(status="CLOSED_TEMP")
        ride = RideFactory(park=park, status="OPERATING")
        user = UserFactory()

        # Reopen park
        park.open(user=user)

        assert park.status == "OPERATING"
        ride.refresh_from_db()
        assert ride.status == "OPERATING"
