"""
Integration tests for Park lifecycle workflows.

This module tests end-to-end park lifecycle workflows including:
- Park opening workflow
- Park temporary closure workflow
- Park permanent closure workflow
- Park relocation workflow
- Related ride status updates
"""

from django.contrib.auth import get_user_model
from django.test import TestCase
from django.utils import timezone

User = get_user_model()


class ParkOpeningWorkflowTests(TestCase):
    """Tests for park opening workflow."""

    @classmethod
    def setUpTestData(cls):
        cls.user = User.objects.create_user(
            username="park_user", email="park_user@example.com", password="testpass123", role="USER"
        )
        cls.moderator = User.objects.create_user(
            username="park_mod", email="park_mod@example.com", password="testpass123", role="MODERATOR"
        )

    def _create_park(self, status="OPERATING", **kwargs):
        """Helper to create a park."""
        from apps.parks.models import Company, Park

        operator = Company.objects.create(name=f"Operator {status}", roles=["OPERATOR"])

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

    def test_park_opens_from_under_construction(self):
        """
        Test park opening from under construction state.

        Flow: UNDER_CONSTRUCTION → OPERATING
        """
        park = self._create_park(status="UNDER_CONSTRUCTION")

        self.assertEqual(park.status, "UNDER_CONSTRUCTION")

        # Park opens
        park.transition_to_operating(user=self.user)
        park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "OPERATING")


class ParkTemporaryClosureWorkflowTests(TestCase):
    """Tests for park temporary closure workflow."""

    @classmethod
    def setUpTestData(cls):
        cls.user = User.objects.create_user(
            username="temp_closure_user", email="temp_closure@example.com", password="testpass123", role="USER"
        )

    def _create_park(self, status="OPERATING", **kwargs):
        from apps.parks.models import Company, Park

        operator = Company.objects.create(name=f"Operator Temp {timezone.now().timestamp()}", roles=["OPERATOR"])

        defaults = {
            "name": f"Test Park Temp {timezone.now().timestamp()}",
            "slug": f"test-park-temp-{timezone.now().timestamp()}",
            "operator": operator,
            "status": status,
            "timezone": "America/New_York",
        }
        defaults.update(kwargs)
        return Park.objects.create(**defaults)

    def test_park_temporary_closure_and_reopen(self):
        """
        Test park temporary closure and reopening.

        Flow: OPERATING → CLOSED_TEMP → OPERATING
        """
        park = self._create_park(status="OPERATING")

        self.assertEqual(park.status, "OPERATING")

        # Close temporarily (e.g., off-season)
        park.transition_to_closed_temp(user=self.user)
        park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "CLOSED_TEMP")

        # Reopen
        park.transition_to_operating(user=self.user)
        park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "OPERATING")


class ParkPermanentClosureWorkflowTests(TestCase):
    """Tests for park permanent closure workflow."""

    @classmethod
    def setUpTestData(cls):
        cls.moderator = User.objects.create_user(
            username="perm_mod", email="perm_mod@example.com", password="testpass123", role="MODERATOR"
        )

    def _create_park(self, status="OPERATING", **kwargs):
        from apps.parks.models import Company, Park

        operator = Company.objects.create(name=f"Operator Perm {timezone.now().timestamp()}", roles=["OPERATOR"])

        defaults = {
            "name": f"Test Park Perm {timezone.now().timestamp()}",
            "slug": f"test-park-perm-{timezone.now().timestamp()}",
            "operator": operator,
            "status": status,
            "timezone": "America/New_York",
        }
        defaults.update(kwargs)
        return Park.objects.create(**defaults)

    def test_park_permanent_closure(self):
        """
        Test park permanent closure from operating state.

        Flow: OPERATING → CLOSED_PERM
        """
        park = self._create_park(status="OPERATING")

        # Close permanently
        park.transition_to_closed_perm(user=self.moderator)
        park.closing_date = timezone.now().date()
        park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "CLOSED_PERM")
        self.assertIsNotNone(park.closing_date)

    def test_park_permanent_closure_from_temp(self):
        """
        Test park permanent closure from temporary closure.

        Flow: OPERATING → CLOSED_TEMP → CLOSED_PERM
        """
        park = self._create_park(status="OPERATING")

        # Temporary closure
        park.transition_to_closed_temp(user=self.moderator)
        park.save()

        # Becomes permanent
        park.transition_to_closed_perm(user=self.moderator)
        park.closing_date = timezone.now().date()
        park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "CLOSED_PERM")


class ParkDemolitionWorkflowTests(TestCase):
    """Tests for park demolition workflow."""

    @classmethod
    def setUpTestData(cls):
        cls.moderator = User.objects.create_user(
            username="demo_mod", email="demo_mod@example.com", password="testpass123", role="MODERATOR"
        )

    def _create_park(self, status="CLOSED_PERM", **kwargs):
        from apps.parks.models import Company, Park

        operator = Company.objects.create(name=f"Operator Demo {timezone.now().timestamp()}", roles=["OPERATOR"])

        defaults = {
            "name": f"Test Park Demo {timezone.now().timestamp()}",
            "slug": f"test-park-demo-{timezone.now().timestamp()}",
            "operator": operator,
            "status": status,
            "timezone": "America/New_York",
        }
        defaults.update(kwargs)
        return Park.objects.create(**defaults)

    def test_park_demolition_workflow(self):
        """
        Test complete park demolition workflow.

        Flow: OPERATING → CLOSED_PERM → DEMOLISHED
        """
        park = self._create_park(status="CLOSED_PERM")

        # Demolish
        park.transition_to_demolished(user=self.moderator)
        park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "DEMOLISHED")

    def test_demolished_is_final_state(self):
        """Test that demolished parks cannot transition further."""
        from django_fsm import TransitionNotAllowed

        park = self._create_park(status="DEMOLISHED")

        # Cannot transition from demolished
        with self.assertRaises(TransitionNotAllowed):
            park.transition_to_operating(user=self.moderator)


class ParkRelocationWorkflowTests(TestCase):
    """Tests for park relocation workflow."""

    @classmethod
    def setUpTestData(cls):
        cls.moderator = User.objects.create_user(
            username="reloc_mod", email="reloc_mod@example.com", password="testpass123", role="MODERATOR"
        )

    def _create_park(self, status="CLOSED_PERM", **kwargs):
        from apps.parks.models import Company, Park

        operator = Company.objects.create(name=f"Operator Reloc {timezone.now().timestamp()}", roles=["OPERATOR"])

        defaults = {
            "name": f"Test Park Reloc {timezone.now().timestamp()}",
            "slug": f"test-park-reloc-{timezone.now().timestamp()}",
            "operator": operator,
            "status": status,
            "timezone": "America/New_York",
        }
        defaults.update(kwargs)
        return Park.objects.create(**defaults)

    def test_park_relocation_workflow(self):
        """
        Test park relocation workflow.

        Flow: OPERATING → CLOSED_PERM → RELOCATED
        """
        park = self._create_park(status="CLOSED_PERM")

        # Relocate
        park.transition_to_relocated(user=self.moderator)
        park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "RELOCATED")

    def test_relocated_is_final_state(self):
        """Test that relocated parks cannot transition further."""
        from django_fsm import TransitionNotAllowed

        park = self._create_park(status="RELOCATED")

        # Cannot transition from relocated
        with self.assertRaises(TransitionNotAllowed):
            park.transition_to_operating(user=self.moderator)


class ParkWrapperMethodTests(TestCase):
    """Tests for park wrapper methods."""

    @classmethod
    def setUpTestData(cls):
        cls.user = User.objects.create_user(
            username="wrapper_user", email="wrapper@example.com", password="testpass123", role="USER"
        )
        cls.moderator = User.objects.create_user(
            username="wrapper_mod", email="wrapper_mod@example.com", password="testpass123", role="MODERATOR"
        )

    def _create_park(self, status="OPERATING", **kwargs):
        from apps.parks.models import Company, Park

        operator = Company.objects.create(name=f"Operator Wrapper {timezone.now().timestamp()}", roles=["OPERATOR"])

        defaults = {
            "name": f"Test Park Wrapper {timezone.now().timestamp()}",
            "slug": f"test-park-wrapper-{timezone.now().timestamp()}",
            "operator": operator,
            "status": status,
            "timezone": "America/New_York",
        }
        defaults.update(kwargs)
        return Park.objects.create(**defaults)

    def test_close_temporarily_wrapper(self):
        """Test close_temporarily wrapper method."""
        park = self._create_park(status="OPERATING")

        # Use wrapper method if it exists
        if hasattr(park, "close_temporarily"):
            park.close_temporarily(user=self.user)
        else:
            park.transition_to_closed_temp(user=self.user)
            park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "CLOSED_TEMP")

    def test_reopen_wrapper(self):
        """Test reopen wrapper method."""
        park = self._create_park(status="CLOSED_TEMP")

        # Use wrapper method if it exists
        if hasattr(park, "reopen"):
            park.reopen(user=self.user)
        else:
            park.transition_to_operating(user=self.user)
            park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "OPERATING")

    def test_close_permanently_wrapper(self):
        """Test close_permanently wrapper method."""
        park = self._create_park(status="OPERATING")
        closing_date = timezone.now().date()

        # Use wrapper method if it exists
        if hasattr(park, "close_permanently"):
            park.close_permanently(closing_date=closing_date, user=self.moderator)
        else:
            park.transition_to_closed_perm(user=self.moderator)
            park.closing_date = closing_date
            park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "CLOSED_PERM")

    def test_demolish_wrapper(self):
        """Test demolish wrapper method."""
        park = self._create_park(status="CLOSED_PERM")

        # Use wrapper method if it exists
        if hasattr(park, "demolish"):
            park.demolish(user=self.moderator)
        else:
            park.transition_to_demolished(user=self.moderator)
            park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "DEMOLISHED")

    def test_relocate_wrapper(self):
        """Test relocate wrapper method."""
        park = self._create_park(status="CLOSED_PERM")

        # Use wrapper method if it exists
        if hasattr(park, "relocate"):
            park.relocate(user=self.moderator)
        else:
            park.transition_to_relocated(user=self.moderator)
            park.save()

        park.refresh_from_db()
        self.assertEqual(park.status, "RELOCATED")


class ParkStateLogTests(TestCase):
    """Tests for StateLog entries on park transitions."""

    @classmethod
    def setUpTestData(cls):
        cls.user = User.objects.create_user(
            username="log_user", email="log_user@example.com", password="testpass123", role="USER"
        )
        cls.moderator = User.objects.create_user(
            username="log_mod", email="log_mod@example.com", password="testpass123", role="MODERATOR"
        )

    def _create_park(self, status="OPERATING", **kwargs):
        from apps.parks.models import Company, Park

        operator = Company.objects.create(name=f"Operator Log {timezone.now().timestamp()}", roles=["OPERATOR"])

        defaults = {
            "name": f"Test Park Log {timezone.now().timestamp()}",
            "slug": f"test-park-log-{timezone.now().timestamp()}",
            "operator": operator,
            "status": status,
            "timezone": "America/New_York",
        }
        defaults.update(kwargs)
        return Park.objects.create(**defaults)

    def test_transition_creates_state_log(self):
        """Test that park transitions create StateLog entries."""
        from django.contrib.contenttypes.models import ContentType
        from django_fsm_log.models import StateLog

        park = self._create_park(status="OPERATING")
        park_ct = ContentType.objects.get_for_model(park)

        # Perform transition
        park.transition_to_closed_temp(user=self.user)
        park.save()

        # Check log was created
        log = StateLog.objects.filter(content_type=park_ct, object_id=park.id).first()

        self.assertIsNotNone(log, "StateLog entry should be created")
        self.assertEqual(log.state, "CLOSED_TEMP")
        self.assertEqual(log.by, self.user)

    def test_multiple_transitions_logged(self):
        """Test that multiple park transitions are all logged."""
        from django.contrib.contenttypes.models import ContentType
        from django_fsm_log.models import StateLog

        park = self._create_park(status="OPERATING")
        park_ct = ContentType.objects.get_for_model(park)

        # First transition: OPERATING -> CLOSED_TEMP
        park.transition_to_closed_temp(user=self.user)
        park.save()

        # Second transition: CLOSED_TEMP -> CLOSED_PERM
        park.transition_to_closed_perm(user=self.moderator)
        park.save()

        # Check multiple logs created
        logs = StateLog.objects.filter(content_type=park_ct, object_id=park.id).order_by("timestamp")

        self.assertEqual(logs.count(), 2, "Should have 2 log entries")
        self.assertEqual(logs[0].state, "CLOSED_TEMP")
        self.assertEqual(logs[0].by, self.user)
        self.assertEqual(logs[1].state, "CLOSED_PERM")
        self.assertEqual(logs[1].by, self.moderator)

    def test_full_lifecycle_logged(self):
        """Test complete park lifecycle is logged."""
        from django.contrib.contenttypes.models import ContentType
        from django_fsm_log.models import StateLog

        park = self._create_park(status="OPERATING")
        park_ct = ContentType.objects.get_for_model(park)

        # Full lifecycle: OPERATING -> CLOSED_TEMP -> OPERATING -> CLOSED_PERM -> DEMOLISHED
        park.transition_to_closed_temp(user=self.user)
        park.save()

        park.transition_to_operating(user=self.user)
        park.save()

        park.transition_to_closed_perm(user=self.moderator)
        park.save()

        park.transition_to_demolished(user=self.moderator)
        park.save()

        # Check all logs created
        logs = StateLog.objects.filter(content_type=park_ct, object_id=park.id).order_by("timestamp")

        self.assertEqual(logs.count(), 4, "Should have 4 log entries")
        states = [log.state for log in logs]
        self.assertEqual(states, ["CLOSED_TEMP", "OPERATING", "CLOSED_PERM", "DEMOLISHED"])
