import pytest
from django.test import Client
from django.urls import reverse

from apps.parks.forms import ParkAutocomplete, ParkSearchForm
from apps.parks.models import Park


@pytest.mark.django_db
class TestParkSearch:
    def test_autocomplete_results(self, client: Client):
        """Test that autocomplete returns correct results"""
        # Create test parks
        park1 = Park.objects.create(name="Test Park")
        park2 = Park.objects.create(name="Another Park")
        park3 = Park.objects.create(name="Test Garden")

        # Get autocomplete results
        url = reverse("parks:suggest_parks")
        response = client.get(url, {"search": "Test"})

        # Check response
        assert response.status_code == 200
        content = response.content.decode()
        assert park1.name in content
        assert park3.name in content
        assert park2.name not in content

    def test_search_form_valid(self):
        """Test ParkSearchForm validation"""
        form = ParkSearchForm(data={})
        assert form.is_valid()

    def test_autocomplete_class(self):
        """Test ParkAutocomplete configuration"""
        ac = ParkAutocomplete()
        assert ac.model == Park
        assert "name" in ac.search_attrs

    def test_search_with_filters(self, client: Client):
        """Test search works with filters"""
        park = Park.objects.create(name="Test Park", status="OPERATING")

        # Search with status filter
        url = reverse("parks:park_list")
        response = client.get(url, {"park": str(park.pk), "status": "OPERATING"})

        assert response.status_code == 200
        assert park.name in response.content.decode()

    def test_empty_search(self, client: Client):
        """Test empty search returns all parks"""
        Park.objects.create(name="Test Park")
        Park.objects.create(name="Another Park")

        url = reverse("parks:park_list")
        response = client.get(url)

        assert response.status_code == 200
        content = response.content.decode()
        assert "Test Park" in content
        assert "Another Park" in content

    def test_partial_match_search(self, client: Client):
        """Test partial matching in search"""
        Park.objects.create(name="Adventure World")
        Park.objects.create(name="Water Adventure")

        url = reverse("parks:suggest_parks")
        response = client.get(url, {"search": "Adv"})

        assert response.status_code == 200
        content = response.content.decode()
        assert "Adventure World" in content
        assert "Water Adventure" in content

    def test_htmx_request_handling(self, client: Client):
        """Test HTMX-specific request handling"""
        Park.objects.create(name="Test Park")

        url = reverse("parks:suggest_parks")
        response = client.get(url, {"search": "Test"}, HTTP_HX_REQUEST="true")

        assert response.status_code == 200
        assert "Test Park" in response.content.decode()

    def test_view_mode_persistence(self, client: Client):
        """Test view mode is maintained during search"""
        Park.objects.create(name="Test Park")

        url = reverse("parks:park_list")
        response = client.get(url, {"park": "Test", "view_mode": "list"})

        assert response.status_code == 200
        assert 'data-view-mode="list"' in response.content.decode()

    def test_suggestion_limit(self, client: Client):
        """Test that suggestions are limited to 8 items"""
        # Create 10 parks
        for i in range(10):
            Park.objects.create(name=f"Test Park {i}")

        url = reverse("parks:suggest_parks")
        response = client.get(url, {"search": "Test"})

        content = response.content.decode()
        result_count = content.count("Test Park")
        assert result_count == 8  # Verify limit is enforced

    def test_search_json_format(self, client: Client):
        """Test that search returns properly formatted JSON"""
        park = Park.objects.create(
            name="Test Park",
            status="OPERATING",
            city="Test City",
            state="Test State",
        )

        url = reverse("parks:suggest_parks")
        response = client.get(url, {"search": "Test"})

        assert response.status_code == 200
        data = response.json()
        assert "results" in data
        assert len(data["results"]) == 1

        result = data["results"][0]
        assert result["id"] == str(park.pk)
        assert result["name"] == "Test Park"
        assert result["status"] == "Operating"
        assert result["location"] == park.formatted_location
        assert result["url"] == reverse("parks:park_detail", kwargs={"slug": park.slug})

    def test_empty_search_json(self, client: Client):
        """Test empty search returns empty results array"""
        url = reverse("parks:suggest_parks")
        response = client.get(url, {"search": ""})

        assert response.status_code == 200
        data = response.json()
        assert "results" in data
        assert len(data["results"]) == 0

    def test_search_format_validation(self, client: Client):
        """Test that all fields are properly formatted in search results"""
        Park.objects.create(
            name="Test Park",
            status="OPERATING",
            city="Test City",
            state="Test State",
            country="Test Country",
        )

        expected_fields = {"id", "name", "status", "location", "url"}

        url = reverse("parks:suggest_parks")
        response = client.get(url, {"search": "Test"})
        data = response.json()
        result = data["results"][0]

        # Check all expected fields are present
        assert set(result.keys()) == expected_fields

        # Check field types
        assert isinstance(result["id"], str)
        assert isinstance(result["name"], str)
        assert isinstance(result["status"], str)
        assert isinstance(result["location"], str)
        assert isinstance(result["url"], str)

        # Check formatted location includes city and state
        assert "Test City" in result["location"]
        assert "Test State" in result["location"]
