"""
Test cases for Parks API following Django styleguide patterns.
Comprehensive API endpoint testing with proper naming conventions.
"""

from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient, APITestCase

from apps.parks.models import Park
from tests.factories import (
    CompanyFactory,
    ParkFactory,
    StaffUserFactory,
    UserFactory,
)


class TestParkListApi(APITestCase):
    """Test cases for Park list API endpoint."""

    def setUp(self):
        """Set up test data."""
        self.client = APIClient()
        self.user = UserFactory()
        self.company = CompanyFactory(roles=["OPERATOR"])
        self.parks = [
            ParkFactory(operator=self.company, name="Park A"),
            ParkFactory(operator=self.company, name="Park B", status="CLOSED_TEMP"),
            ParkFactory(operator=self.company, name="Park C"),
        ]
        self.url = reverse("parks_api:park-list")

    def test__park_list_api__unauthenticated_user__can_access(self):
        """Test that unauthenticated users can access park list."""
        response = self.client.get(self.url)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data["status"], "success")
        self.assertIsInstance(response.data["data"], list)

    def test__park_list_api__returns_all_parks__in_correct_format(self):
        """Test that park list returns all parks in correct format."""
        response = self.client.get(self.url)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data["data"]), 3)

        # Check response structure
        park_data = response.data["data"][0]
        expected_fields = [
            "id",
            "name",
            "slug",
            "status",
            "description",
            "average_rating",
            "coaster_count",
            "ride_count",
            "location",
            "operator",
            "created_at",
            "updated_at",
        ]

        for field in expected_fields:
            self.assertIn(field, park_data)

    def test__park_list_api__with_status_filter__returns_filtered_results(
        self,
    ):
        """Test that status filter works correctly."""
        response = self.client.get(self.url, {"status": "OPERATING"})

        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # Should return only operating parks (2 out of 3)
        operating_parks = [p for p in response.data["data"] if p["status"] == "OPERATING"]
        self.assertEqual(len(operating_parks), 2)

    def test__park_list_api__with_search_query__returns_matching_results(self):
        """Test that search functionality works correctly."""
        response = self.client.get(self.url, {"search": "Park A"})

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data["data"]), 1)
        self.assertEqual(response.data["data"][0]["name"], "Park A")

    def test__park_list_api__with_ordering__returns_ordered_results(self):
        """Test that ordering functionality works correctly."""
        response = self.client.get(self.url, {"ordering": "-name"})

        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # Should be ordered by name descending (C, B, A)
        names = [park["name"] for park in response.data["data"]]
        self.assertEqual(names, ["Park C", "Park B", "Park A"])


class TestParkDetailApi(APITestCase):
    """Test cases for Park detail API endpoint."""

    def setUp(self):
        """Set up test data."""
        self.client = APIClient()
        self.company = CompanyFactory(roles=["OPERATOR"])
        self.park = ParkFactory(operator=self.company)
        self.url = reverse("parks_api:park-detail", kwargs={"slug": self.park.slug})

    def test__park_detail_api__with_valid_slug__returns_park_details(self):
        """Test that park detail API returns correct park information."""
        response = self.client.get(self.url)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data["status"], "success")

        park_data = response.data["data"]
        self.assertEqual(park_data["id"], self.park.id)
        self.assertEqual(park_data["name"], self.park.name)
        self.assertEqual(park_data["slug"], self.park.slug)

        # Check that detailed fields are included
        detailed_fields = [
            "opening_date",
            "closing_date",
            "operating_season",
            "size_acres",
            "website",
            "areas",
            "operator",
            "property_owner",
        ]

        for field in detailed_fields:
            self.assertIn(field, park_data)

    def test__park_detail_api__with_invalid_slug__returns_404(self):
        """Test that invalid slug returns 404 error."""
        invalid_url = reverse("parks_api:park-detail", kwargs={"slug": "nonexistent"})
        response = self.client.get(invalid_url)

        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
        self.assertEqual(response.data["status"], "error")
        self.assertEqual(response.data["error"]["code"], "NOT_FOUND")


class TestParkCreateApi(APITestCase):
    """Test cases for Park creation API endpoint."""

    def setUp(self):
        """Set up test data."""
        self.client = APIClient()
        self.user = UserFactory()
        self.staff_user = StaffUserFactory()
        self.company = CompanyFactory(roles=["OPERATOR"])
        self.url = reverse("parks_api:park-list")  # POST to list endpoint

        self.valid_park_data = {
            "name": "New Test Park",
            "description": "A test park for API testing",
            "operator_id": self.company.id,
            "status": "OPERATING",
        }

    def test__park_create_api__unauthenticated_user__returns_401(self):
        """Test that unauthenticated users cannot create parks."""
        response = self.client.post(self.url, self.valid_park_data)

        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test__park_create_api__authenticated_user__can_create_park(self):
        """Test that authenticated users can create parks."""
        self.client.force_authenticate(user=self.user)
        response = self.client.post(self.url, self.valid_park_data)

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data["status"], "success")

        # Verify park was created
        park_data = response.data["data"]
        self.assertEqual(park_data["name"], "New Test Park")
        self.assertTrue(Park.objects.filter(name="New Test Park").exists())

    def test__park_create_api__with_invalid_data__returns_validation_errors(
        self,
    ):
        """Test that invalid data returns proper validation errors."""
        self.client.force_authenticate(user=self.user)

        invalid_data = self.valid_park_data.copy()
        invalid_data["name"] = ""  # Empty name should be invalid

        response = self.client.post(self.url, invalid_data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data["status"], "error")
        self.assertIn("name", response.data["error"]["details"])

    def test__park_create_api__with_invalid_date_range__returns_validation_error(
        self,
    ):
        """Test that invalid date ranges are caught by validation."""
        self.client.force_authenticate(user=self.user)

        invalid_data = self.valid_park_data.copy()
        invalid_data.update(
            {
                "opening_date": "2020-06-01",
                "closing_date": "2020-05-01",  # Before opening date
            }
        )

        response = self.client.post(self.url, invalid_data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn("Closing date cannot be before opening date", str(response.data))


class TestParkUpdateApi(APITestCase):
    """Test cases for Park update API endpoint."""

    def setUp(self):
        """Set up test data."""
        self.client = APIClient()
        self.user = UserFactory()
        self.company = CompanyFactory(roles=["OPERATOR"])
        self.park = ParkFactory(operator=self.company)
        self.url = reverse("parks_api:park-detail", kwargs={"slug": self.park.slug})

    def test__park_update_api__authenticated_user__can_update_park(self):
        """Test that authenticated users can update parks."""
        self.client.force_authenticate(user=self.user)

        update_data = {
            "name": "Updated Park Name",
            "description": "Updated description",
        }

        response = self.client.patch(self.url, update_data)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data["status"], "success")

        # Verify park was updated
        self.park.refresh_from_db()
        self.assertEqual(self.park.name, "Updated Park Name")
        self.assertEqual(self.park.description, "Updated description")

    def test__park_update_api__with_invalid_data__returns_validation_errors(
        self,
    ):
        """Test that invalid update data returns validation errors."""
        self.client.force_authenticate(user=self.user)

        invalid_data = {
            "opening_date": "2020-06-01",
            "closing_date": "2020-05-01",  # Invalid date range
        }

        response = self.client.patch(self.url, invalid_data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)


class TestParkStatsApi(APITestCase):
    """Test cases for Park statistics API endpoint."""

    def setUp(self):
        """Set up test data."""
        self.client = APIClient()
        self.company = CompanyFactory(roles=["OPERATOR"])

        # Create parks with different statuses
        ParkFactory(operator=self.company, status="OPERATING")
        ParkFactory(operator=self.company, status="OPERATING")
        ParkFactory(operator=self.company, status="CLOSED_TEMP")

        self.url = reverse("parks_api:park-stats")

    def test__park_stats_api__returns_correct_statistics(self):
        """Test that park statistics API returns correct data."""
        response = self.client.get(self.url)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data["status"], "success")

        stats = response.data["data"]
        expected_fields = [
            "total_parks",
            "operating_parks",
            "closed_parks",
            "under_construction",
            "average_rating",
            "recently_added_count",
        ]

        for field in expected_fields:
            self.assertIn(field, stats)

        # Verify counts are correct
        self.assertEqual(stats["total_parks"], 3)
        self.assertEqual(stats["operating_parks"], 2)


class TestParkApiErrorHandling(APITestCase):
    """Test cases for Park API error handling."""

    def setUp(self):
        """Set up test data."""
        self.client = APIClient()

    def test__park_api__with_malformed_json__returns_parse_error(self):
        """Test that malformed JSON returns proper error."""
        url = reverse("parks_api:park-list")

        response = self.client.post(url, data='{"invalid": json}', content_type="application/json")

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(response.data["status"], "error")

    def test__park_api__with_unsupported_method__returns_405(self):
        """Test that unsupported HTTP methods return 405."""
        park = ParkFactory()
        url = reverse("parks_api:park-detail", kwargs={"slug": park.slug})

        response = self.client.head(url)  # HEAD not supported

        self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)


class TestParkApiIntegration(APITestCase):
    """Integration tests for Park API with complete scenarios."""

    def test__complete_park_workflow__create_update_retrieve_delete(self):
        """Test complete CRUD workflow for parks."""
        user = UserFactory()
        company = CompanyFactory(roles=["OPERATOR"])
        self.client.force_authenticate(user=user)

        # 1. Create park
        create_data = {
            "name": "Integration Test Park",
            "description": "A park for integration testing",
            "operator_id": company.id,
        }

        create_response = self.client.post(reverse("parks_api:park-list"), create_data)

        self.assertEqual(create_response.status_code, status.HTTP_201_CREATED)
        park_slug = create_response.data["data"]["slug"]

        # 2. Retrieve park
        detail_url = reverse("parks_api:park-detail", kwargs={"slug": park_slug})
        retrieve_response = self.client.get(detail_url)

        self.assertEqual(retrieve_response.status_code, status.HTTP_200_OK)
        self.assertEqual(retrieve_response.data["data"]["name"], "Integration Test Park")

        # 3. Update park
        update_data = {"description": "Updated integration test description"}
        update_response = self.client.patch(detail_url, update_data)

        self.assertEqual(update_response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            update_response.data["data"]["description"],
            "Updated integration test description",
        )

        # 4. Delete park
        delete_response = self.client.delete(detail_url)

        self.assertEqual(delete_response.status_code, status.HTTP_204_NO_CONTENT)

        # 5. Verify park is deleted
        verify_response = self.client.get(detail_url)
        self.assertEqual(verify_response.status_code, status.HTTP_404_NOT_FOUND)
