defmodule MvWeb.MemberLive.IndexGroupsIntegrationTest do
  @moduledoc """
  Tests for integration of groups with existing features in the member overview.

  Tests cover:
  - Groups column works with Field Visibility (column can be hidden)
  - Groups filter works with Custom Field filters
  - Groups sorting works with other sortings
  - Groups work with Membership Fee Status filter
  - Groups work with existing search (but not testing search integration itself)
  - Member index search by group name returns members in that group (Issue #375)
  """
  # async: false to prevent PostgreSQL deadlocks when creating members and groups
  use MvWeb.ConnCase, async: false
  import Phoenix.LiveViewTest
  require Ash.Query

  alias Mv.Helpers.SystemActor
  alias Mv.Membership.{CustomField, CustomFieldValue, Group, MemberGroup}
  alias Mv.MembershipFees.{MembershipFeeCycle, MembershipFeeType}

  setup do
    system_actor = SystemActor.get_system_actor()

    # Create test members
    {:ok, member1} =
      Mv.Membership.create_member(
        %{first_name: "Alice", last_name: "Anderson", email: "alice@example.com"},
        actor: system_actor
      )

    {:ok, member2} =
      Mv.Membership.create_member(
        %{first_name: "Bob", last_name: "Brown", email: "bob@example.com"},
        actor: system_actor
      )

    # Create test groups
    {:ok, group1} =
      Group
      |> Ash.Changeset.for_create(:create, %{name: "Board Members"})
      |> Ash.create(actor: system_actor)

    # Create member-group associations
    {:ok, _mg1} =
      MemberGroup
      |> Ash.Changeset.for_create(:create, %{member_id: member1.id, group_id: group1.id})
      |> Ash.create(actor: system_actor)

    # Create custom field for filter integration test
    {:ok, custom_field} =
      CustomField
      |> Ash.Changeset.for_create(:create, %{
        name: "newsletter",
        value_type: :boolean,
        show_in_overview: false
      })
      |> Ash.create(actor: system_actor)

    # Create custom field value for member1
    {:ok, _cfv} =
      CustomFieldValue
      |> Ash.Changeset.for_create(:create, %{
        member_id: member1.id,
        custom_field_id: custom_field.id,
        value: %{"_union_type" => "boolean", "_union_value" => true}
      })
      |> Ash.create(actor: system_actor)

    %{
      member1: member1,
      member2: member2,
      group1: group1,
      custom_field: custom_field
    }
  end

  test "groups column works with field visibility", %{
    conn: conn,
    member1: member1,
    group1: group1
  } do
    conn = conn_with_oidc_user(conn)
    {:ok, _view, html} = live(conn, "/members")

    # Verify groups column is visible by default (header and content)
    assert html =~ group1.name
    assert html =~ member1.first_name
    assert html =~ "Groups"
  end

  test "groups filter works with custom field filters", %{
    conn: conn,
    member1: member1,
    group1: group1
  } do
    # Verify group filter applies; boolean filters live in the filter dropdown and
    # are exercised in member filter tests. Here we only assert group filter works.
    conn = conn_with_oidc_user(conn)
    {:ok, view, _html} = live(conn, "/members")

    view
    |> element("button[aria-label='Filter members']")
    |> render_click()

    view
    |> element("[data-testid='member-filter-form']")
    |> render_change(%{"group_#{group1.id}" => "in", "payment_filter" => "all"})

    html = render(view)
    assert html =~ member1.first_name
  end

  test "groups sorting works with other sortings", %{
    conn: conn,
    member1: member1,
    member2: member2
  } do
    conn = conn_with_oidc_user(conn)
    {:ok, view, _html} = live(conn, "/members?sort_field=first_name&sort_order=asc")

    # Apply groups sorting (should combine with existing sort)
    view
    |> element("[data-testid='groups']")
    |> render_click()

    # Verify both sorts are applied (or groups sort replaces first_name sort)
    html = render(view)
    assert html =~ member1.first_name
    assert html =~ member2.first_name

    # Sort by groups was applied (URL may include query= and other default params)
    assert has_element?(view, "[data-testid='groups'][aria-label*='ascending']")
  end

  test "groups work with membership fee status filter", %{
    conn: conn,
    member1: member1,
    group1: group1
  } do
    system_actor = SystemActor.get_system_actor()

    # Create a membership fee type and cycle for member1
    {:ok, fee_type} =
      MembershipFeeType
      |> Ash.Changeset.for_create(:create, %{
        name: "Test Fee",
        amount: Decimal.new("50.00"),
        interval: :yearly
      })
      |> Ash.create(actor: system_actor)

    # Set member's fee type so get_last_completed_cycle finds the cycle (uses member.membership_fee_type)
    {:ok, _member1} =
      Mv.Membership.update_member(member1, %{membership_fee_type_id: fee_type.id},
        actor: system_actor
      )

    {:ok, _cycle} =
      MembershipFeeCycle
      |> Ash.Changeset.for_create(:create, %{
        member_id: member1.id,
        membership_fee_type_id: fee_type.id,
        cycle_start: ~D[2024-01-01],
        amount: Decimal.new("50.00"),
        status: :paid
      })
      |> Ash.create(actor: system_actor)

    conn = conn_with_oidc_user(conn)

    {:ok, _view, html} =
      live(conn, "/members?group_#{group1.id}=in&cycle_status_filter=paid")

    assert html =~ "Members"
    # member1 has a group and a paid cycle; page should load with both filters
    assert html =~ member1.first_name
  end

  test "groups work with existing search (not testing search integration)", %{
    conn: conn,
    member1: member1,
    member2: member2,
    group1: group1
  } do
    conn = conn_with_oidc_user(conn)
    {:ok, view, _html} = live(conn, "/members")

    # Apply group filter
    view
    |> element("button[aria-label='Filter members']")
    |> render_click()

    view
    |> element("[data-testid='member-filter-form']")
    |> render_change(%{"group_#{group1.id}" => "in", "payment_filter" => "all"})

    # Apply search (this tests that filter and search work together;
    # search form is in SearchBarComponent with phx-submit="search")
    view
    |> element("form[phx-submit='search']")
    |> render_submit(%{"query" => "Alice"})

    # Verify filter and search both work
    html = render(view)
    assert html =~ member1.first_name
    refute html =~ member2.first_name

    # Note: We're not testing that group names are searchable
    # (that's part of Issue #5 - Search Integration)
  end

  test "member index search by group name returns members in that group", %{
    conn: conn,
    member1: member1,
    member2: member2,
    group1: group1
  } do
    # member1 is in group1 "Board Members", member2 is not
    conn = conn_with_oidc_user(conn)
    {:ok, view, _html} = live(conn, "/members")

    view
    |> element("form[phx-submit='search']")
    |> render_submit(%{"query" => group1.name})

    html = render(view)
    assert html =~ member1.first_name
    refute html =~ member2.first_name
  end

  test "all filters and sortings work together", %{
    conn: conn,
    member1: member1,
    group1: group1
  } do
    conn = conn_with_oidc_user(conn)
    {:ok, view, _html} = live(conn, "/members")

    # Apply group filter
    view
    |> element("button[aria-label='Filter members']")
    |> render_click()

    view
    |> element("[data-testid='member-filter-form']")
    |> render_change(%{"group_#{group1.id}" => "in", "payment_filter" => "all"})

    # Apply sorting
    view
    |> element("[data-testid='groups']")
    |> render_click()

    # Apply search
    view
    |> element("form[phx-submit='search']")
    |> render_submit(%{"query" => "Alice"})

    # Verify group filter, sort, and search are all applied
    html = render(view)
    assert html =~ member1.first_name
    assert has_element?(view, "[data-testid='groups'][aria-label*='ascending']")
  end
end
