defmodule MvWeb.MemberLive.FormMembershipFeeTypeTest do
  @moduledoc """
  Tests for membership fee type dropdown in member form.
  """
  use MvWeb.ConnCase, async: false

  import Phoenix.LiveViewTest

  alias Mv.MembershipFees.MembershipFeeType

  require Ash.Query

  # Helper to create a membership fee type
  # Uses admin_user to test permissions (UI-/Permissions-nah)
  defp create_fee_type(attrs, admin_user) do
    default_attrs = %{
      name: "Test Fee Type #{System.unique_integer([:positive])}",
      amount: Decimal.new("50.00"),
      interval: :yearly
    }

    attrs = Map.merge(default_attrs, attrs)

    MembershipFeeType
    |> Ash.Changeset.for_create(:create, attrs)
    |> Ash.create!(actor: admin_user)
  end

  # Helper to create a member
  # Uses admin_user to test permissions (UI-/Permissions-nah)
  defp create_member(attrs, admin_user) do
    default_attrs = %{
      first_name: "Test",
      last_name: "Member",
      email: "test.member.#{System.unique_integer([:positive])}@example.com"
    }

    attrs = Map.merge(default_attrs, attrs)
    {:ok, member} = Mv.Membership.create_member(attrs, actor: admin_user)
    member
  end

  describe "membership fee type dropdown" do
    test "displays in form", %{conn: conn} do
      {:ok, _view, html} = live(conn, "/members/new")

      # Should show membership fee type dropdown
      assert html =~ "membership_fee_type_id" || html =~ "Membership Fee Type" ||
               html =~ "Beitragsart"
    end

    test "shows available types", %{conn: conn, current_user: admin_user} do
      _fee_type1 = create_fee_type(%{name: "Type 1", interval: :yearly}, admin_user)
      _fee_type2 = create_fee_type(%{name: "Type 2", interval: :yearly}, admin_user)

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

      assert html =~ "Type 1"
      assert html =~ "Type 2"
    end

    test "filters to same interval types if member has type", %{
      conn: conn,
      current_user: admin_user
    } do
      yearly_type = create_fee_type(%{name: "Yearly Type", interval: :yearly}, admin_user)
      _monthly_type = create_fee_type(%{name: "Monthly Type", interval: :monthly}, admin_user)

      member = create_member(%{membership_fee_type_id: yearly_type.id}, admin_user)

      {:ok, _view, html} = live(conn, "/members/#{member.id}/edit")

      # Should show yearly type but not monthly
      assert html =~ "Yearly Type"
      refute html =~ "Monthly Type"
    end

    test "shows warning if different interval selected", %{conn: conn, current_user: admin_user} do
      yearly_type = create_fee_type(%{name: "Yearly Type", interval: :yearly}, admin_user)
      monthly_type = create_fee_type(%{name: "Monthly Type", interval: :monthly}, admin_user)

      member = create_member(%{membership_fee_type_id: yearly_type.id}, admin_user)

      {:ok, _view, html} = live(conn, "/members/#{member.id}/edit")

      # Monthly type should not be in the dropdown (filtered by interval)
      refute html =~ monthly_type.id

      # Only yearly types should be available
      assert html =~ yearly_type.id
    end

    test "warning cleared if same interval selected", %{conn: conn, current_user: admin_user} do
      yearly_type1 = create_fee_type(%{name: "Yearly Type 1", interval: :yearly}, admin_user)
      yearly_type2 = create_fee_type(%{name: "Yearly Type 2", interval: :yearly}, admin_user)

      member = create_member(%{membership_fee_type_id: yearly_type1.id}, admin_user)

      {:ok, view, _html} = live(conn, "/members/#{member.id}/edit")

      # Select another yearly type (should not show warning)
      html =
        view
        |> form("#member-form", %{"member[membership_fee_type_id]" => yearly_type2.id})
        |> render_change()

      refute html =~ "Warning" || html =~ "Warnung"
    end

    test "form saves with selected membership fee type", %{conn: conn, current_user: admin_user} do
      fee_type = create_fee_type(%{interval: :yearly}, admin_user)

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

      form_data = %{
        "member[first_name]" => "Test",
        "member[last_name]" => "Member",
        "member[email]" => "test#{System.unique_integer([:positive])}@example.com",
        "member[membership_fee_type_id]" => fee_type.id
      }

      {:error, {:live_redirect, %{to: _to}}} =
        view
        |> form("#member-form", form_data)
        |> render_submit()

      # Verify member was created with fee type - use admin_user to test permissions
      member =
        Mv.Membership.Member
        |> Ash.Query.filter(email == ^form_data["member[email]"])
        |> Ash.read_one!(actor: admin_user)

      assert member.membership_fee_type_id == fee_type.id
    end

    test "new members get default membership fee type", %{conn: conn, current_user: admin_user} do
      # Set default fee type in settings
      fee_type = create_fee_type(%{interval: :yearly}, admin_user)

      {:ok, settings} = Mv.Membership.get_settings()

      settings
      |> Ash.Changeset.for_update(:update_membership_fee_settings, %{
        default_membership_fee_type_id: fee_type.id
      })
      |> Ash.update!(actor: admin_user)

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

      # Form should have default fee type selected
      html = render(view)
      assert html =~ fee_type.name || html =~ "selected"
    end
  end

  describe "custom field value preservation" do
    test "custom field values preserved when membership fee type changes", %{
      conn: conn,
      current_user: admin_user
    } do
      # Create custom field - use admin_user to test permissions
      custom_field =
        Mv.Membership.CustomField
        |> Ash.Changeset.for_create(:create, %{
          name: "Test Field",
          value_type: :string,
          required: false
        })
        |> Ash.create!(actor: admin_user)

      # Create two fee types with same interval
      fee_type1 = create_fee_type(%{name: "Type 1", interval: :yearly}, admin_user)
      fee_type2 = create_fee_type(%{name: "Type 2", interval: :yearly}, admin_user)

      # Create member with fee type 1 and custom field value
      member =
        create_member(
          %{
            first_name: "Test",
            last_name: "Member",
            email: "test#{System.unique_integer([:positive])}@example.com",
            membership_fee_type_id: fee_type1.id
          },
          admin_user
        )

      # Add custom field value
      Mv.Membership.CustomFieldValue
      |> Ash.Changeset.for_create(:create, %{
        member_id: member.id,
        custom_field_id: custom_field.id,
        value: %{"_union_type" => "string", "_union_value" => "Test Value"}
      })
      |> Ash.create!(actor: admin_user)

      {:ok, view, _html} = live(conn, "/members/#{member.id}/edit")

      # Change membership fee type dropdown
      html =
        view
        |> form("#member-form", %{"member[membership_fee_type_id]" => fee_type2.id})
        |> render_change()

      # Verify custom field value is still present (check for field name or value)
      assert html =~ custom_field.name || html =~ "Test Value"
    end

    test "union/typed values roundtrip correctly", %{conn: conn, current_user: admin_user} do
      # Create date custom field - use admin_user to test permissions
      custom_field =
        Mv.Membership.CustomField
        |> Ash.Changeset.for_create(:create, %{
          name: "Date Field",
          value_type: :date,
          required: false
        })
        |> Ash.create!(actor: admin_user)

      fee_type = create_fee_type(%{interval: :yearly}, admin_user)

      # Create member with date custom field value
      member =
        create_member(
          %{
            first_name: "Test",
            last_name: "Member",
            email: "test#{System.unique_integer([:positive])}@example.com",
            membership_fee_type_id: fee_type.id
          },
          admin_user
        )

      test_date = ~D[2024-01-15]

      # Add date custom field value
      Mv.Membership.CustomFieldValue
      |> Ash.Changeset.for_create(:create, %{
        member_id: member.id,
        custom_field_id: custom_field.id,
        value: %{"_union_type" => "date", "_union_value" => test_date}
      })
      |> Ash.create!(actor: admin_user)

      {:ok, view, _html} = live(conn, "/members/#{member.id}/edit")

      # Trigger validation (simulates dropdown change)
      html =
        view
        |> form("#member-form", %{"member[membership_fee_type_id]" => fee_type.id})
        |> render_change()

      # Verify date value is still present (check for date input or formatted date)
      assert html =~ "2024" || html =~ "date"
    end

    test "removing custom field values works correctly", %{conn: conn, current_user: admin_user} do
      # Create custom field - use admin_user to test permissions
      custom_field =
        Mv.Membership.CustomField
        |> Ash.Changeset.for_create(:create, %{
          name: "Test Field",
          value_type: :string,
          required: false
        })
        |> Ash.create!(actor: admin_user)

      fee_type = create_fee_type(%{interval: :yearly}, admin_user)

      # Create member with custom field value
      member =
        create_member(
          %{
            first_name: "Test",
            last_name: "Member",
            email: "test#{System.unique_integer([:positive])}@example.com",
            membership_fee_type_id: fee_type.id
          },
          admin_user
        )

      # Add custom field value
      _cfv =
        Mv.Membership.CustomFieldValue
        |> Ash.Changeset.for_create(:create, %{
          member_id: member.id,
          custom_field_id: custom_field.id,
          value: %{"_union_type" => "string", "_union_value" => "Test Value"}
        })
        |> Ash.create!(actor: admin_user)

      {:ok, view, _html} = live(conn, "/members/#{member.id}/edit")

      # Change membership fee type to trigger validation
      # This should preserve the custom field value
      html =
        view
        |> form("#member-form", %{
          "member[membership_fee_type_id]" => fee_type.id
        })
        |> render_change()

      # Form should still be valid and custom field value should be preserved
      # The custom field value should still be visible in the form
      assert html =~ "Test Value" || html =~ custom_field.name
    end
  end
end
