defmodule MvWeb.GroupLive.ShowTest do
  @moduledoc """
  Tests for the group detail page.

  Tests cover:
  - Displaying group information
  - Slug-based routing
  - Member list display
  - Navigation
  - Error handling
  - Delete functionality
  """
  use MvWeb.ConnCase, async: false
  import Phoenix.LiveViewTest
  require Ash.Query
  use Gettext, backend: MvWeb.Gettext

  alias Mv.Membership
  alias Mv.Fixtures

  describe "mount and display" do
    test "page renders successfully", %{conn: conn} do
      group = Fixtures.group_fixture()

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "h1", group.name)
    end

    test "displays group name", %{conn: conn} do
      group = Fixtures.group_fixture(%{name: "Test Group Name"})

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "h1", "Test Group Name")
    end

    test "displays group description when present", %{conn: conn} do
      group = Fixtures.group_fixture(%{description: "This is a test description"})

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "p", "This is a test description")
    end

    test "displays member count", %{conn: conn} do
      group = Fixtures.group_fixture()

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "[data-testid=group-show-member-count]")
    end

    test "displays list of members in group", %{conn: conn} do
      group = Fixtures.group_fixture()
      member1 = Fixtures.member_fixture(%{first_name: "Alice", last_name: "Smith"})
      member2 = Fixtures.member_fixture(%{first_name: "Bob", last_name: "Jones"})

      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
      )

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "[data-testid=group-show-members-table]", "Alice")
      assert has_element?(view, "[data-testid=group-show-members-table]", "Bob")
    end

    test "displays edit button for admin users", %{conn: conn} do
      group = Fixtures.group_fixture()

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "[data-testid=group-show-edit-btn]")
    end

    test "displays delete button for admin users", %{conn: conn} do
      group = Fixtures.group_fixture()

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "[data-testid=group-show-delete-btn]")
    end
  end

  describe "slug-based routing" do
    test "route /groups/:slug works correctly", %{conn: conn} do
      group = Fixtures.group_fixture(%{name: "Board Members"})

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "h1", "Board Members")
    end

    test "group is found by slug via unique_slug identity", %{conn: conn} do
      group = Fixtures.group_fixture(%{name: "Test Group"})

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "h1", group.name)
    end

    test "non-existent slug returns 404", %{conn: conn} do
      non_existent_slug = "non-existent-group-slug"

      result = live(conn, "/groups/#{non_existent_slug}")

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

    test "slug is case-sensitive (exact match required)", %{conn: conn} do
      group = Fixtures.group_fixture(%{name: "Test Group"})
      # Slug should be lowercase
      wrong_case_slug = String.upcase(group.slug)

      result = live(conn, "/groups/#{wrong_case_slug}")

      # Should not find group with wrong case
      assert match?({:error, {:redirect, %{to: "/groups"}}}, result) ||
               match?({:error, {:live_redirect, %{to: "/groups"}}}, result)
    end

    test "URL is readable and user-friendly", %{conn: conn} do
      group = Fixtures.group_fixture(%{name: "Board Members"})

      {:ok, _view, _html} = live(conn, "/groups/#{group.slug}")

      # URL should contain readable slug, not UUID
      assert group.slug == "board-members"
      refute String.contains?(group.slug, "-") == false
    end
  end

  describe "edge cases" do
    test "displays empty group correctly (0 members)", %{conn: conn} do
      group = Fixtures.group_fixture()

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "[data-testid=group-show-no-members]")
    end

    test "handles group without description correctly", %{conn: conn} do
      group = Fixtures.group_fixture(%{description: nil})

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "h1", group.name)
    end

    test "handles slug with special characters correctly", %{conn: conn} do
      # Create group with name that generates slug with hyphens
      group = Fixtures.group_fixture(%{name: "Test-Group-Name"})

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "h1", group.name)
    end
  end

  describe "security" do
    @tag role: :member
    test "read-only users can view group detail page", %{conn: conn} do
      group = Fixtures.group_fixture()
      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/#{group.slug}")

      assert has_element?(view, "h1", group.name)
      refute has_element?(view, "[data-testid=group-show-edit-btn]")
      refute has_element?(view, "[data-testid=group-show-delete-btn]")
    end

    @tag role: :unauthenticated
    test "unauthenticated users are redirected to login", %{conn: conn} do
      group = Fixtures.group_fixture()

      result = live(conn, "/groups/#{group.slug}")

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

    test "slug injection attempts are prevented", %{conn: conn} do
      # Try to inject SQL or other malicious content in slug
      malicious_slug = "'; DROP TABLE groups; --"

      result = live(conn, "/groups/#{malicious_slug}")

      # Should not execute SQL, should return 404 or error
      assert match?({:error, {:redirect, %{to: "/groups"}}}, result) ||
               match?({:error, {:live_redirect, %{to: "/groups"}}}, result)
    end

    test "user cannot delete group with non-existent slug", %{conn: conn} do
      # This test verifies that delete action (if accessed via URL manipulation)
      # cannot be performed with non-existent slug
      # Note: Actual delete functionality will be tested when delete modal is implemented
      non_existent_slug = "non-existent-group-slug"

      # Attempting to access show page with non-existent slug should fail
      result = live(conn, "/groups/#{non_existent_slug}")

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

  describe "performance" do
    @describetag :slow
    test "member list is loaded efficiently (no N+1 queries)", %{conn: conn} do
      group = Fixtures.group_fixture()

      # Create multiple members
      members = Enum.map(1..5, fn _ -> Fixtures.member_fixture() end)

      system_actor = Mv.Helpers.SystemActor.get_system_actor()

      # Add all members to group
      Enum.each(members, fn member ->
        Membership.create_member_group(%{member_id: member.id, group_id: group.id},
          actor: system_actor
        )
      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)

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

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

      Enum.each(members, fn member ->
        assert has_element?(view, "[data-testid=group-show-members-table]", member.first_name) or
                 has_element?(view, "[data-testid=group-show-members-table]", member.last_name)
      end)

      # Verify query count is reasonable (should avoid N+1 queries)
      # Expected: 1 query for group lookup + 1 query for members (with preload) + member_count aggregate
      # Allow overhead for authorization, LiveView setup, and other initialization queries
      # Note: member_count aggregate and authorization checks may add additional queries
      assert final_count <= 20,
             "Expected max 20 queries (group + members preload + member_count aggregate + LiveView setup + auth), got #{final_count}. This suggests N+1 query problem."
    end

    test "slug lookup is efficient (uses unique_slug index)", %{conn: conn} do
      group = Fixtures.group_fixture()

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert has_element?(view, "h1", group.name)
    end
  end

  describe "navigation" do
    test "back button navigates to groups list", %{conn: conn} do
      group = Fixtures.group_fixture()

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      assert {:error, {:live_redirect, %{to: to}}} =
               view
               |> element(
                 "a[aria-label*='Back'], button[aria-label*='Back'], a[aria-label*='groups list'], button[aria-label*='groups list']"
               )
               |> render_click()

      assert to == "/groups"
    end

    test "edit button navigates to edit form", %{conn: conn} do
      group = Fixtures.group_fixture()

      {:ok, view, _html} = live(conn, "/groups/#{group.slug}")

      # Button with navigate is rendered as <a> tag via <.link>
      # Use element with text content to find the link
      assert {:error, {:live_redirect, %{to: to}}} =
               view
               |> element("a", gettext("Edit"))
               |> render_click()

      assert to == "/groups/#{group.slug}/edit"
    end
  end
end
