defmodule Mv.Membership.MembershipFeeSettingsTest do
  @moduledoc """
  Tests for membership fee settings in the Settings resource.
  """
  use Mv.DataCase, async: true

  alias Mv.Membership.Setting
  alias Mv.MembershipFees.MembershipFeeType

  setup do
    system_actor = Mv.Helpers.SystemActor.get_system_actor()
    %{actor: system_actor}
  end

  describe "membership fee settings" do
    test "default values are correct" do
      {:ok, settings} = Mv.Membership.get_settings()
      assert settings.include_joining_cycle == true
    end

    test "settings can be read" do
      {:ok, settings} = Mv.Membership.get_settings()
      assert %Setting{} = settings
    end

    test "settings can be written via update_membership_fee_settings", %{actor: actor} do
      {:ok, settings} = Mv.Membership.get_settings()

      {:ok, updated} =
        settings
        |> Ash.Changeset.for_update(:update_membership_fee_settings, %{
          include_joining_cycle: false
        })
        |> Ash.update(actor: actor)

      assert updated.include_joining_cycle == false
    end

    test "default_membership_fee_type_id can be nil (optional)", %{actor: actor} do
      {:ok, settings} = Mv.Membership.get_settings()

      {:ok, updated} =
        settings
        |> Ash.Changeset.for_update(:update_membership_fee_settings, %{
          default_membership_fee_type_id: nil
        })
        |> Ash.update(actor: actor)

      assert updated.default_membership_fee_type_id == nil
    end

    test "default_membership_fee_type_id validation: must exist if set", %{actor: actor} do
      {:ok, settings} = Mv.Membership.get_settings()

      # Create a valid fee type
      {:ok, fee_type} =
        Ash.create(
          MembershipFeeType,
          %{
            name: "Test Fee Type #{System.unique_integer([:positive])}",
            amount: Decimal.new("100.00"),
            interval: :yearly
          },
          actor: actor
        )

      # Setting a valid fee type should work
      {:ok, updated} =
        settings
        |> Ash.Changeset.for_update(
          :update_membership_fee_settings,
          %{
            default_membership_fee_type_id: fee_type.id
          },
          actor: actor
        )
        |> Ash.update(actor: actor)

      assert updated.default_membership_fee_type_id == fee_type.id
    end

    test "default_membership_fee_type_id validation: fails if not found", %{actor: actor} do
      {:ok, settings} = Mv.Membership.get_settings()

      # Use a non-existent UUID
      fake_uuid = Ecto.UUID.generate()

      assert {:error, error} =
               settings
               |> Ash.Changeset.for_update(:update_membership_fee_settings, %{
                 default_membership_fee_type_id: fake_uuid
               })
               |> Ash.update(actor: actor)

      assert error_on_field?(error, :default_membership_fee_type_id)
    end
  end

  # Helper to check if an error occurred on a specific field
  defp error_on_field?(%Ash.Error.Invalid{} = error, field) do
    Enum.any?(error.errors, fn e ->
      case e do
        %{field: ^field} -> true
        %{fields: fields} when is_list(fields) -> field in fields
        _ -> false
      end
    end)
  end

  defp error_on_field?(_, _), do: false
end
