"""
Tests for Ride forms.

Following Django styleguide pattern: test__<context>__<action>__<expected_outcome>
"""

import pytest
from django.test import TestCase

from apps.rides.forms import (
    RideForm,
    RideSearchForm,
)
from tests.factories import (
    DesignerCompanyFactory,
    ManufacturerCompanyFactory,
    ParkAreaFactory,
    ParkFactory,
    RideFactory,
    RideModelFactory,
)


@pytest.mark.django_db
class TestRideForm(TestCase):
    """Tests for RideForm."""

    def test__init__no_park__shows_park_search_field(self):
        """Test initializing without park shows park search field."""
        form = RideForm()

        assert "park_search" in form.fields
        assert "park" in form.fields

    def test__init__with_park__hides_park_search_field(self):
        """Test initializing with park hides park search field."""
        park = ParkFactory()
        form = RideForm(park=park)

        assert "park_search" not in form.fields
        assert "park" in form.fields
        assert form.fields["park"].initial == park

    def test__init__with_park__populates_park_area_queryset(self):
        """Test initializing with park populates park_area choices."""
        park = ParkFactory()
        area1 = ParkAreaFactory(park=park, name="Area 1")
        area2 = ParkAreaFactory(park=park, name="Area 2")

        form = RideForm(park=park)

        # Park area queryset should contain park's areas
        queryset = form.fields["park_area"].queryset
        assert area1 in queryset
        assert area2 in queryset

    def test__init__without_park__park_area_disabled(self):
        """Test initializing without park disables park_area."""
        form = RideForm()

        assert form.fields["park_area"].widget.attrs.get("disabled") is True

    def test__init__existing_ride__prefills_manufacturer(self):
        """Test initializing with existing ride prefills manufacturer."""
        manufacturer = ManufacturerCompanyFactory(name="Test Manufacturer")
        ride = RideFactory(manufacturer=manufacturer)

        form = RideForm(instance=ride)

        assert form.fields["manufacturer_search"].initial == "Test Manufacturer"
        assert form.fields["manufacturer"].initial == manufacturer

    def test__init__existing_ride__prefills_designer(self):
        """Test initializing with existing ride prefills designer."""
        designer = DesignerCompanyFactory(name="Test Designer")
        ride = RideFactory(designer=designer)

        form = RideForm(instance=ride)

        assert form.fields["designer_search"].initial == "Test Designer"
        assert form.fields["designer"].initial == designer

    def test__init__existing_ride__prefills_ride_model(self):
        """Test initializing with existing ride prefills ride model."""
        ride_model = RideModelFactory(name="Test Model")
        ride = RideFactory(ride_model=ride_model)

        form = RideForm(instance=ride)

        assert form.fields["ride_model_search"].initial == "Test Model"
        assert form.fields["ride_model"].initial == ride_model

    def test__init__existing_ride_without_park_arg__prefills_park_search(self):
        """Test initializing with existing ride prefills park search."""
        park = ParkFactory(name="Test Park")
        ride = RideFactory(park=park)

        form = RideForm(instance=ride)

        assert form.fields["park_search"].initial == "Test Park"
        assert form.fields["park"].initial == park

    def test__init__category_is_required(self):
        """Test category field is required."""
        form = RideForm()

        assert form.fields["category"].required is True

    def test__init__date_fields_have_no_initial_value(self):
        """Test date fields have no initial value."""
        form = RideForm()

        assert form.fields["opening_date"].initial is None
        assert form.fields["closing_date"].initial is None
        assert form.fields["status_since"].initial is None

    def test__field_order__matches_expected(self):
        """Test fields are ordered correctly."""
        form = RideForm()

        expected_order = [
            "park_search",
            "park",
            "park_area",
            "name",
            "manufacturer_search",
            "manufacturer",
            "designer_search",
            "designer",
            "ride_model_search",
            "ride_model",
            "category",
        ]

        # Get first 11 fields from form
        actual_order = list(form.fields.keys())[:11]

        assert actual_order == expected_order

    def test__validate__valid_data__is_valid(self):
        """Test form is valid with all required data."""
        park = ParkFactory()
        manufacturer = ManufacturerCompanyFactory()

        data = {
            "name": "Test Ride",
            "park": park.pk,
            "category": "RC",  # Roller coaster
            "status": "OPERATING",
            "manufacturer": manufacturer.pk,
        }

        form = RideForm(data=data)

        # Remove park_search validation error by skipping it
        if "park_search" in form.errors:
            del form.errors["park_search"]

        # Check if form would be valid otherwise
        assert "name" not in form.errors
        assert "category" not in form.errors

    def test__validate__missing_name__returns_error(self):
        """Test form is invalid without name."""
        park = ParkFactory()

        data = {
            "park": park.pk,
            "category": "RC",
            "status": "OPERATING",
        }

        form = RideForm(data=data)
        is_valid = form.is_valid()

        assert not is_valid
        assert "name" in form.errors

    def test__validate__missing_category__returns_error(self):
        """Test form is invalid without category."""
        park = ParkFactory()

        data = {
            "name": "Test Ride",
            "park": park.pk,
            "status": "OPERATING",
        }

        form = RideForm(data=data)
        is_valid = form.is_valid()

        assert not is_valid
        assert "category" in form.errors

    def test__widgets__name_field__has_styling(self):
        """Test name field has appropriate CSS classes."""
        form = RideForm()

        name_widget = form.fields["name"].widget
        assert "class" in name_widget.attrs
        assert "rounded-lg" in name_widget.attrs["class"]

    def test__widgets__category_field__has_htmx_attributes(self):
        """Test category field has HTMX attributes."""
        form = RideForm()

        category_widget = form.fields["category"].widget
        assert "hx-get" in category_widget.attrs
        assert "hx-target" in category_widget.attrs
        assert "hx-trigger" in category_widget.attrs

    def test__widgets__status_field__has_alpine_attributes(self):
        """Test status field has Alpine.js attributes."""
        form = RideForm()

        status_widget = form.fields["status"].widget
        assert "x-model" in status_widget.attrs
        assert "@change" in status_widget.attrs

    def test__widgets__closing_date__has_conditional_display(self):
        """Test closing_date has conditional display logic."""
        form = RideForm()

        closing_date_widget = form.fields["closing_date"].widget
        assert "x-show" in closing_date_widget.attrs

    def test__meta__model__is_ride(self):
        """Test Meta.model is Ride."""
        from apps.rides.models import Ride

        assert RideForm.Meta.model == Ride

    def test__meta__fields__includes_expected_fields(self):
        """Test Meta.fields includes expected ride fields."""
        expected_fields = [
            "name",
            "category",
            "status",
            "opening_date",
            "closing_date",
            "min_height_in",
            "max_height_in",
            "description",
        ]

        for field in expected_fields:
            assert field in RideForm.Meta.fields


@pytest.mark.django_db
class TestRideSearchForm(TestCase):
    """Tests for RideSearchForm."""

    def test__init__creates_ride_field(self):
        """Test initializing form creates ride field."""
        form = RideSearchForm()

        assert "ride" in form.fields

    def test__ride_field__not_required(self):
        """Test ride field is not required."""
        form = RideSearchForm()

        assert form.fields["ride"].required is False

    def test__ride_field__uses_select_widget(self):
        """Test ride field uses Select widget."""
        form = RideSearchForm()

        widget = form.fields["ride"].widget
        assert "Select" in widget.__class__.__name__

    def test__ride_field__has_htmx_attributes(self):
        """Test ride field has HTMX attributes."""
        form = RideSearchForm()

        ride_widget = form.fields["ride"].widget
        assert "hx-get" in ride_widget.attrs
        assert "hx-trigger" in ride_widget.attrs
        assert "hx-target" in ride_widget.attrs

    def test__validate__empty_form__is_valid(self):
        """Test empty form is valid."""
        form = RideSearchForm(data={})

        assert form.is_valid()

    def test__validate__with_ride__is_valid(self):
        """Test form with valid ride is valid."""
        ride = RideFactory()
        form = RideSearchForm(data={"ride": ride.pk})

        assert form.is_valid()

    def test__validate__with_invalid_ride__is_invalid(self):
        """Test form with invalid ride is invalid."""
        form = RideSearchForm(data={"ride": 99999})

        assert not form.is_valid()
        assert "ride" in form.errors


@pytest.mark.django_db
class TestRideFormWithParkAreas(TestCase):
    """Tests for RideForm park area functionality."""

    def test__park_area__queryset_empty_without_park(self):
        """Test park_area queryset is empty when no park provided."""
        form = RideForm()

        # When no park, the queryset should be empty (none())
        queryset = form.fields["park_area"].queryset
        assert queryset.count() == 0

    def test__park_area__queryset_filtered_to_park(self):
        """Test park_area queryset only contains areas from given park."""
        park1 = ParkFactory()
        park2 = ParkFactory()
        area1 = ParkAreaFactory(park=park1)
        area2 = ParkAreaFactory(park=park2)

        form = RideForm(park=park1)

        queryset = form.fields["park_area"].queryset
        assert area1 in queryset
        assert area2 not in queryset

    def test__park_area__is_optional(self):
        """Test park_area field is optional."""
        form = RideForm()

        assert form.fields["park_area"].required is False


@pytest.mark.django_db
class TestRideFormFieldOrder(TestCase):
    """Tests for RideForm field ordering."""

    def test__field_order__park_fields_first(self):
        """Test park-related fields come first."""
        form = RideForm()

        field_names = list(form.fields.keys())

        # park_search should be first
        assert field_names[0] == "park_search"
        assert field_names[1] == "park"
        assert field_names[2] == "park_area"

    def test__field_order__name_after_park(self):
        """Test name field comes after park fields."""
        form = RideForm()

        field_names = list(form.fields.keys())

        name_index = field_names.index("name")
        park_index = field_names.index("park")

        assert name_index > park_index

    def test__field_order__description_last(self):
        """Test description is near the end."""
        form = RideForm()

        field_names = list(form.fields.keys())

        # Description should be one of the last fields
        description_index = field_names.index("description")
        assert description_index > len(field_names) // 2
