defmodule MvWeb.GroupLive.FormTest do
  @moduledoc """
  Tests for the group create/edit form.

  Tests cover:
  - Creating groups
  - Editing groups
  - Form validations
  - Edge cases
  - Security
  """
  use MvWeb.ConnCase, async: false
  import Phoenix.LiveViewTest
  use Gettext, backend: MvWeb.Gettext

  alias Mv.Fixtures

  describe "create form" do
    test "form renders with empty fields", %{conn: conn} do
      {:ok, view, html} = live(conn, "/groups/new")

      # OR-chain for i18n (Create Group / Gruppe erstellen)
      assert html =~ gettext("Create Group") or html =~ "create" or html =~ "Gruppe erstellen"
      assert has_element?(view, "form")
    end

    test "creates group successfully with name and description", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/groups/new")

      form_data = %{
        "name" => "New Group",
        "description" => "Group description"
      }

      view
      |> form("#group-form", group: form_data)
      |> render_submit()

      # Should redirect to groups list or show page
      assert_redirect(view, "/groups")
    end

    test "creates group successfully with name only (description optional)", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/groups/new")

      form_data = %{
        "name" => "Group Without Description"
      }

      view
      |> form("#group-form", group: form_data)
      |> render_submit()

      assert_redirect(view, "/groups")
    end

    test "shows error when name is missing", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/groups/new")

      form_data = %{
        "description" => "Description without name"
      }

      html =
        view
        |> form("#group-form", group: form_data)
        |> render_submit()

      # OR-chain for i18n (required/erforderlich) and validation message wording
      assert html =~ gettext("required") or html =~ "name" or html =~ "error" or
               html =~ "erforderlich"
    end

    test "shows error when name exceeds 100 characters", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/groups/new")

      long_name = String.duplicate("a", 101)
      form_data = %{"name" => long_name}

      html =
        view
        |> form("#group-form", group: form_data)
        |> render_submit()

      # OR-chain for i18n (length/Länge) and validation message
      assert html =~ "100" or html =~ "length" or html =~ "error" or html =~ "Länge"
    end

    test "shows error when description exceeds 500 characters", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/groups/new")

      long_description = String.duplicate("a", 501)

      form_data = %{
        "name" => "Test Group",
        "description" => long_description
      }

      html =
        view
        |> form("#group-form", group: form_data)
        |> render_submit()

      # OR-chain for i18n (length/Länge) and validation message
      assert html =~ "500" or html =~ "length" or html =~ "error" or html =~ "Länge"
    end

    test "shows error when name already exists (case-insensitive)", %{conn: conn} do
      _existing_group = Fixtures.group_fixture(%{name: "Existing Group"})

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

      form_data = %{
        "name" => "EXISTING GROUP"
      }

      html =
        view
        |> form("#group-form", group: form_data)
        |> render_submit()

      # Check for a validation error on the name field in a robust way
      # OR-chain for i18n and validation message (already taken)
      assert html =~ "name" or html =~ gettext("has already been taken")
    end

    test "shows error when name generates empty slug", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/groups/new")

      form_data = %{
        "name" => "!!!"
      }

      html =
        view
        |> form("#group-form", group: form_data)
        |> render_submit()

      # OR-chain for i18n (error/Fehler, invalid/ungültig)
      assert html =~ "error" or html =~ "invalid" or html =~ "Fehler" or html =~ "ungültig"
    end
  end

  describe "edit form" do
    test "form renders with existing group data", %{conn: conn} do
      group =
        Fixtures.group_fixture(%{name: "Original Name", description: "Original Description"})

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

      assert html =~ "Original Name"
      assert html =~ "Original Description"
      assert has_element?(view, "form")
    end

    test "updates group name successfully (slug remains unchanged)", %{conn: conn} do
      group = Fixtures.group_fixture(%{name: "Original Name"})
      original_slug = group.slug

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

      form_data = %{
        "name" => "Updated Name"
      }

      view
      |> form("#group-form", group: form_data)
      |> render_submit()

      # Verify slug didn't change by checking redirect URL or reloading
      assert_redirect(view, "/groups/#{original_slug}")
    end

    test "updates group description successfully", %{conn: conn} do
      group = Fixtures.group_fixture(%{description: "Old Description"})

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

      form_data = %{
        "description" => "New Description"
      }

      view
      |> form("#group-form", group: form_data)
      |> render_submit()

      assert_redirect(view, "/groups/#{group.slug}")
    end

    test "shows error when updating to duplicate name (case-insensitive)", %{conn: conn} do
      _group1 = Fixtures.group_fixture(%{name: "Group One"})
      group2 = Fixtures.group_fixture(%{name: "Group Two"})

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

      form_data = %{
        "name" => "GROUP ONE"
      }

      html =
        view
        |> form("#group-form", group: form_data)
        |> render_submit()

      # OR-chain for i18n (already taken / bereits vergeben) and validation wording
      assert html =~ "already" or html =~ "taken" or html =~ "exists" or html =~ "error" or
               html =~ "bereits" or html =~ "vergeben"
    end

    test "slug is not displayed in form (immutable)", %{conn: conn} do
      group = Fixtures.group_fixture(%{name: "Test Group"})

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

      # Slug should not be in form (it's immutable); regex for input element
      refute html =~ ~r/slug.*input/i or html =~ ~r/input.*slug/i
    end
  end

  describe "edge cases" do
    test "handles whitespace trimming correctly", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/groups/new")

      form_data = %{
        "name" => "  Trimmed Group  "
      }

      view
      |> form("#group-form", group: form_data)
      |> render_submit()

      # Name should be trimmed
      assert_redirect(view, "/groups")
    end

    test "handles umlauts in name correctly", %{conn: conn} do
      {:ok, view, _html} = live(conn, "/groups/new")

      form_data = %{
        "name" => "Müller Gruppe"
      }

      view
      |> form("#group-form", group: form_data)
      |> render_submit()

      assert_redirect(view, "/groups")
    end
  end

  describe "security" do
    @tag role: :member
    test "non-admin users cannot access create form", %{conn: conn} do
      result = live(conn, "/groups/new")

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

    @tag role: :member
    test "non-admin users cannot access edit form", %{conn: conn} do
      group = Fixtures.group_fixture()

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

      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/new")

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

    test "user cannot edit group with non-existent slug", %{conn: conn} do
      non_existent_slug = "non-existent-group-slug"

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

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

    test "user cannot edit group with wrong slug (case mismatch)", %{conn: conn} do
      group = Fixtures.group_fixture(%{name: "Test Group"})
      wrong_case_slug = String.upcase(group.slug)

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

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