defmodule MvWeb.Components.MemberFilterComponentTest do
  @moduledoc """
  Unit tests for the MemberFilterComponent.

  Tests cover:
  - Rendering Payment Filter and Boolean Custom Fields
  - Boolean filter selection and event emission
  - Button label and badge logic
  - Filtering to show only boolean custom fields
  """
  # async: false to prevent PostgreSQL deadlocks when running LiveView tests against DB
  use MvWeb.ConnCase, async: false

  import Phoenix.LiveViewTest
  use Gettext, backend: MvWeb.Gettext

  alias Mv.Membership.CustomField

  # Helper to create a boolean custom field (uses system_actor - only admin can create)
  defp create_boolean_custom_field(attrs \\ %{}) do
    system_actor = Mv.Helpers.SystemActor.get_system_actor()

    default_attrs = %{
      name: "test_boolean_#{System.unique_integer([:positive])}",
      value_type: :boolean
    }

    attrs = Map.merge(default_attrs, attrs)

    CustomField
    |> Ash.Changeset.for_create(:create, attrs)
    |> Ash.create!(actor: system_actor)
  end

  # Helper to create a non-boolean custom field (uses system_actor - only admin can create)
  defp create_string_custom_field(attrs \\ %{}) do
    system_actor = Mv.Helpers.SystemActor.get_system_actor()

    default_attrs = %{
      name: "test_string_#{System.unique_integer([:positive])}",
      value_type: :string
    }

    attrs = Map.merge(default_attrs, attrs)

    CustomField
    |> Ash.Changeset.for_create(:create, attrs)
    |> Ash.create!(actor: system_actor)
  end

  describe "rendering" do
    test "renders boolean custom fields when present", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      boolean_field = create_boolean_custom_field(%{name: "Active Member"})

      {:ok, view, _html} = live(conn, "/members")

      # Should show the boolean custom field name in the dropdown
      view
      |> element("#member-filter button[aria-haspopup='true']")
      |> render_click()

      html = render(view)
      assert html =~ boolean_field.name
    end

    test "renders payment and custom fields groups when boolean fields exist", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      _boolean_field = create_boolean_custom_field()

      {:ok, view, _html} = live(conn, "/members")

      # Open dropdown
      view
      |> element("#member-filter button[aria-haspopup='true']")
      |> render_click()

      html = render(view)
      # Should have both "Payments" and "Custom Fields" group labels
      assert html =~ gettext("Payments") || html =~ "Payment"
      assert html =~ gettext("Custom Fields")
    end

    test "renders only payment filter when no boolean custom fields exist", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      # Create a non-boolean field to ensure it's not shown
      _string_field = create_string_custom_field()

      {:ok, view, _html} = live(conn, "/members")

      # Component should exist with correct ID
      assert has_element?(view, "#member-filter")

      # Open dropdown
      view
      |> element("#member-filter button[aria-haspopup='true']")
      |> render_click()

      html = render(view)

      # Should show payment filter options (check both English and translated)
      assert html =~ "All" || html =~ gettext("All")
      assert html =~ "Paid" || html =~ gettext("Paid")
      assert html =~ "Unpaid" || html =~ gettext("Unpaid")

      # Should not show any boolean field names (since none exist)
      # We can't easily check this without knowing field names, but the structure should be correct
    end
  end

  describe "boolean filter selection" do
    test "selecting boolean filter sends correct event", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      boolean_field = create_boolean_custom_field(%{name: "Newsletter"})

      {:ok, view, _html} = live(conn, "/members")

      # Open dropdown
      view
      |> element("#member-filter button[aria-haspopup='true']")
      |> render_click()

      # Select "True" option for the boolean field using radio input
      # Radio inputs trigger phx-change on the form, so we use render_change on the form
      view
      |> form("#member-filter form", %{
        "custom_boolean" => %{to_string(boolean_field.id) => "true"}
      })
      |> render_change()

      # The event should be sent to the parent LiveView
      # We verify this by checking that the URL is updated
      assert_patch(view)
    end

    test "payment filter still works after component extension", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      _boolean_field = create_boolean_custom_field()

      {:ok, view, _html} = live(conn, "/members")

      # Open dropdown
      view
      |> element("#member-filter button[aria-haspopup='true']")
      |> render_click()

      # Select "Paid" option using radio input
      # Radio inputs trigger phx-change on the form, so we use render_change on the form
      view
      |> form("#member-filter form", %{"payment_filter" => "paid"})
      |> render_change()

      # URL should be updated with cycle_status_filter=paid
      path = assert_patch(view)
      assert path =~ "cycle_status_filter=paid"
    end
  end

  describe "button label" do
    test "shows active boolean filter names in button label", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      boolean_field1 = create_boolean_custom_field(%{name: "Active Member"})
      boolean_field2 = create_boolean_custom_field(%{name: "Newsletter"})

      # Set filters via URL
      {:ok, view, _html} =
        live(
          conn,
          "/members?bf_#{boolean_field1.id}=true&bf_#{boolean_field2.id}=false"
        )

      # Component should exist
      assert has_element?(view, "#member-filter")

      # Button label should contain the custom field names
      # The exact format depends on implementation, but should show active filters
      button_html =
        view
        |> element("#member-filter button[aria-haspopup='true']")
        |> render()

      assert button_html =~ boolean_field1.name || button_html =~ boolean_field2.name
    end

    test "truncates long custom field names in button label", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      # Create field with very long name (>30 characters)
      long_name = String.duplicate("A", 50)
      boolean_field = create_boolean_custom_field(%{name: long_name})

      # Set filter via URL
      {:ok, view, _html} =
        live(conn, "/members?bf_#{boolean_field.id}=true")

      # Component should exist
      assert has_element?(view, "#member-filter")

      # Get button label text
      button_html =
        view
        |> element("#member-filter button[aria-haspopup='true']")
        |> render()

      # Button label should be truncated - full name should NOT appear in button
      # (it may appear in dropdown when opened, but not in the button label itself)
      # Check that button doesn't contain the full 50-character name
      refute button_html =~ long_name

      # Button should still contain some text (truncated version or indicator)
      assert String.length(button_html) > 0
    end
  end

  describe "badge" do
    test "shows total count of active boolean filters in badge", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      boolean_field1 = create_boolean_custom_field(%{name: "Field1"})
      boolean_field2 = create_boolean_custom_field(%{name: "Field2"})

      # Set two filters via URL
      {:ok, view, _html} =
        live(
          conn,
          "/members?bf_#{boolean_field1.id}=true&bf_#{boolean_field2.id}=false"
        )

      # Component should exist
      assert has_element?(view, "#member-filter")

      # Badge should be visible when boolean filters are active
      assert has_element?(view, "#member-filter .badge")

      # Badge should show count of active boolean filters (2 in this case)
      badge_html =
        view
        |> element("#member-filter .badge")
        |> render()

      assert badge_html =~ "2"
    end
  end

  describe "filtering" do
    test "only boolean custom fields are displayed, not string or integer fields", %{conn: conn} do
      conn = conn_with_oidc_user(conn)
      boolean_field = create_boolean_custom_field(%{name: "Boolean Field"})
      _string_field = create_string_custom_field(%{name: "String Field"})

      {:ok, view, _html} = live(conn, "/members")

      # Open dropdown
      view
      |> element("#member-filter button[aria-haspopup='true']")
      |> render_click()

      # Should show boolean field in the dropdown panel
      # Extract only the dropdown panel HTML to check
      dropdown_html =
        view
        |> element("#member-filter div[role='dialog']")
        |> render()

      # Should show boolean field in dropdown
      assert dropdown_html =~ boolean_field.name

      # Should not show string field name in the filter dropdown
      # (String fields should not appear in boolean filter section)
      refute dropdown_html =~ "String Field"
    end

    test "dropdown shows scrollbar when many boolean custom fields exist", %{conn: conn} do
      conn = conn_with_oidc_user(conn)

      # Create 15 boolean custom fields (more than typical, should trigger scrollbar)
      boolean_fields =
        Enum.map(1..15, fn i ->
          create_boolean_custom_field(%{name: "Field #{i}"})
        end)

      {:ok, view, _html} = live(conn, "/members")

      # Open dropdown
      view
      |> element("#member-filter button[aria-haspopup='true']")
      |> render_click()

      # Extract dropdown panel HTML
      dropdown_html =
        view
        |> element("#member-filter div[role='dialog']")
        |> render()

      # Should have scrollbar classes: max-h-60 overflow-y-auto pr-2
      # Check for the scrollable container (the div with max-h-60 and overflow-y-auto)
      assert dropdown_html =~ "max-h-60"
      assert dropdown_html =~ "overflow-y-auto"

      # Verify all fields are present in the dropdown
      Enum.each(boolean_fields, fn field ->
        assert dropdown_html =~ field.name
      end)
    end
  end
end
