defmodule MvWeb.MemberLive.IndexGroupsUrlParamsTest do
  @moduledoc """
  Tests for URL parameter persistence for groups in the member overview.

  Tests cover:
  - Group presence filter is written to URL (group_presence=has_groups|no_groups)
  - Group sorting is written to URL (sort_field=groups&sort_order=asc)
  - URL parameters are restored on load
  - URL parameters work with other parameters (query, sort_field, etc.)
  - URL is bookmarkable (filter/sorting persist)
  """
  # async: false to prevent PostgreSQL deadlocks when creating members and groups
  use MvWeb.ConnCase, async: false
  import Phoenix.LiveViewTest
  require Ash.Query

  alias Mv.Membership.{Group, MemberGroup}

  setup do
    system_actor = Mv.Helpers.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)

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

  test "group filter is written to URL", %{
    conn: conn,
    member1: member1,
    group1: group1
  } do
    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 "group sorting is written to URL", %{
    conn: conn
  } do
    conn = conn_with_oidc_user(conn)
    {:ok, view, _html} = live(conn, "/members")

    # Click on groups column header to sort
    view
    |> element("[data-testid='groups']")
    |> render_click()

    # Verify sort was applied (URL is patched with sort params)
    assert has_element?(view, "[data-testid='groups'][aria-label*='ascending']")
  end

  test "URL parameters are restored on load", %{
    conn: conn,
    member1: member1,
    member2: member2,
    group1: group1
  } do
    conn = conn_with_oidc_user(conn)

    {:ok, view, html} =
      live(conn, "/members?group_#{group1.id}=in&sort_field=groups&sort_order=asc")

    assert html =~ member1.first_name
    refute html =~ member2.first_name
    assert has_element?(view, "[data-testid='groups'][aria-label*='ascending']")
  end

  test "URL parameters work with query parameter", %{
    conn: conn,
    member1: member1,
    group1: group1
  } do
    conn = conn_with_oidc_user(conn)
    {:ok, _view, html} = live(conn, "/members?query=Alice&group_#{group1.id}=in")

    assert html =~ member1.first_name
  end

  test "URL parameters work with other sort fields", %{
    conn: conn,
    member1: member1,
    group1: group1
  } do
    conn = conn_with_oidc_user(conn)

    {:ok, view, html} =
      live(conn, "/members?sort_field=first_name&sort_order=desc&group_#{group1.id}=in")

    assert html =~ member1.first_name
    assert has_element?(view, "[data-testid='first_name'][aria-label*='descending']")
  end

  test "URL is bookmarkable with filter and sorting", %{
    conn: conn,
    member1: member1,
    group1: group1
  } do
    conn = conn_with_oidc_user(conn)
    bookmark_url = "/members?group_#{group1.id}=in&sort_field=groups&sort_order=asc"

    {:ok, view, html} = live(conn, bookmark_url)

    assert html =~ member1.first_name
    assert has_element?(view, "[data-testid='groups'][aria-label*='ascending']")
  end

  test "handles multiple group filter parameters (uses last one)", %{
    conn: conn,
    member1: member1,
    member2: member2,
    group1: group1
  } do
    conn = conn_with_oidc_user(conn)
    # Duplicate param for same group: last wins. group_id=in then not_in -> not_in
    {:ok, _view, html} =
      live(conn, "/members?group_#{group1.id}=in&group_#{group1.id}=not_in")

    # not_in group1: member2 and member3 (member1 is in group1)
    refute html =~ member1.first_name
    assert html =~ member2.first_name
  end

  test "handles invalid URL parameters gracefully", %{
    conn: conn,
    member1: member1,
    member2: member2
  } do
    conn = conn_with_oidc_user(conn)
    invalid_id = Ecto.UUID.generate()
    {:ok, _view, html} = live(conn, "/members?group_#{invalid_id}=in")

    # Unknown group id ignored, all members shown
    assert html =~ member1.first_name
    assert html =~ member2.first_name
  end

  test "handles malformed URL parameters", %{
    conn: conn,
    member1: member1,
    member2: member2
  } do
    conn = conn_with_oidc_user(conn)
    {:ok, _view, html} = live(conn, "/members?group_not-a-uuid=in")

    assert html =~ member1.first_name
    assert html =~ member2.first_name
  end
end
