defmodule MvWeb.GroupLive.IndexTest do
  @moduledoc """
  Tests for the groups overview page.

  Tests cover:
  - Displaying list of groups
  - Creating new groups
  - Deleting groups with confirmation
  - Permission checks
  - Edge cases
  """
  use MvWeb.ConnCase, async: false
  import Phoenix.LiveViewTest
  use Gettext, backend: MvWeb.Gettext

  alias Mv.Membership
  alias Mv.Fixtures

  describe "mount and display" do
    test "page renders successfully for admin user", %{conn: conn} do
      {:ok, _view, html} = live(conn, "/groups")

      assert html =~ gettext("Groups")
    end

    test "lists all groups", %{conn: conn} do
      group1 = Fixtures.group_fixture(%{name: "Group One"})
      group2 = Fixtures.group_fixture(%{name: "Group Two"})

      {:ok, _view, html} = live(conn, "/groups")

      assert html =~ group1.name
      assert html =~ group2.name
    end

    test "displays group name, description, and member count", %{conn: conn} do
      _group = Fixtures.group_fixture(%{name: "Test Group", description: "Test description"})

      {:ok, _view, html} = live(conn, "/groups")

      assert html =~ "Test Group"
      assert html =~ "Test description"
      # OR-chain for i18n (Members/Mitglieder) and alternate copy for count
      assert html =~ "0" or html =~ gettext("Members") or html =~ "Mitglieder"
    end

    test "displays 'Create Group' button for admin users", %{conn: conn} do
      {:ok, _view, html} = live(conn, "/groups")

      # OR-chain for i18n (Create Group / Gruppe erstellen) and alternate wording
      assert html =~ gettext("Create Group") or html =~ "create" or html =~ "new" or
               html =~ "Gruppe erstellen"
    end

    test "displays empty state when no groups exist", %{conn: conn} do
      {:ok, _view, html} = live(conn, "/groups")

      # OR-chain for i18n (No groups / Keine Gruppen) and alternate empty state copy
      assert html =~ gettext("No groups") or html =~ "0" or html =~ "empty" or
               html =~ "Keine Gruppen"
    end
  end

  describe "edge cases" do
    test "handles very long group names correctly", %{conn: conn} do
      long_name = String.duplicate("a", 100)
      _group = Fixtures.group_fixture(%{name: long_name})

      {:ok, _view, html} = live(conn, "/groups")

      assert html =~ long_name
    end

    test "handles very long descriptions correctly", %{conn: conn} do
      long_description = String.duplicate("a", 500)
      _group = Fixtures.group_fixture(%{description: long_description})

      {:ok, _view, html} = live(conn, "/groups")

      # Long description may be truncated in UI
      assert html =~ long_description or html =~ String.slice(long_description, 0, 100)
    end
  end

  describe "security" do
    @tag role: :member
    test "non-admin users cannot access groups page", %{conn: conn} do
      # Should redirect or show 403
      result = live(conn, "/groups")

      assert match?({:error, {:redirect, %{to: _}}}, result) ||
               match?({:error, {:live_redirect, %{to: _}}}, result)
    end

    @tag role: :unauthenticated
    test "unauthenticated users are redirected to login", %{conn: conn} do
      result = live(conn, "/groups")

      assert match?({:error, {:redirect, %{to: "/sign-in"}}}, result) ||
               match?({:error, {:live_redirect, %{to: "/sign-in"}}}, result)
    end

    @tag role: :member
    test "read-only users can view groups but not create", %{conn: conn} do
      # Create read-only user
      read_only_user = Fixtures.user_with_role_fixture("read_only")
      conn = conn_with_password_user(conn, read_only_user)

      {:ok, _view, html} = live(conn, "/groups")

      # Should be able to see groups
      assert html =~ gettext("Groups")

      # Read-only must not see create button (OR for i18n)
      refute html =~ gettext("Create Group") or html =~ "create"
    end
  end

  describe "performance" do
    @describetag :slow
    test "page loads efficiently with many groups", %{conn: conn} do
      # Create multiple groups
      Enum.each(1..10, fn _ -> Fixtures.group_fixture() end)

      # Count queries using Telemetry
      query_count_agent = Agent.start_link(fn -> 0 end) |> elem(1)

      handler = fn _event, _measurements, _metadata, _config ->
        Agent.update(query_count_agent, &(&1 + 1))
      end

      handler_id = "test-query-counter-#{System.unique_integer([:positive])}"
      :telemetry.attach(handler_id, [:ash, :query, :start], handler, nil)

      # Should load without N+1 queries
      {:ok, _view, html} = live(conn, "/groups")

      final_count = Agent.get(query_count_agent, & &1)
      :telemetry.detach(handler_id)

      # Verify all groups are displayed
      assert html =~ gettext("Groups")

      # Verify query count is reasonable (should avoid N+1 queries)
      # Expected: 1 query for groups list + 1 batch query for member counts + LiveView setup queries
      # Allow overhead for authorization, LiveView setup, and other initialization queries
      assert final_count <= 12,
             "Expected max 12 queries (groups list + batch member counts + LiveView setup + auth), got #{final_count}. This suggests N+1 query problem."
    end

    test "member count is loaded efficiently via calculation", %{conn: conn} do
      group = Fixtures.group_fixture()
      member1 = Fixtures.member_fixture()
      member2 = Fixtures.member_fixture()

      # Add members to group
      system_actor = Mv.Helpers.SystemActor.get_system_actor()

      Membership.create_member_group(%{member_id: member1.id, group_id: group.id},
        actor: system_actor
      )

      Membership.create_member_group(%{member_id: member2.id, group_id: group.id},
        actor: system_actor
      )

      # Count queries using Telemetry
      query_count_agent = Agent.start_link(fn -> 0 end) |> elem(1)

      handler = fn _event, _measurements, _metadata, _config ->
        Agent.update(query_count_agent, &(&1 + 1))
      end

      handler_id = "test-query-counter-#{System.unique_integer([:positive])}"
      :telemetry.attach(handler_id, [:ash, :query, :start], handler, nil)

      {:ok, _view, html} = live(conn, "/groups")

      final_count = Agent.get(query_count_agent, & &1)
      :telemetry.detach(handler_id)

      # OR-chain for i18n (Members/Mitglieder) and count display
      assert html =~ "2" or html =~ gettext("Members") or html =~ "Mitglieder"

      # Verify query count is reasonable (member count should be calculated efficiently)
      # Expected: 1 query for groups + 1 batch query for member counts + LiveView setup queries
      # Allow overhead for authorization, LiveView setup, and other initialization queries
      assert final_count <= 12,
             "Expected max 12 queries (groups + batch member counts + LiveView setup + auth), got #{final_count}. This suggests inefficient member count calculation."
    end
  end
end
