defmodule Mv.Membership.SettingTest do
  use Mv.DataCase, async: false
  alias Mv.Membership

  describe "Settings Resource" do
    setup do
      {:ok, settings} = Membership.get_settings()
      saved_visibility = settings.member_field_visibility || %{}
      saved_required = settings.member_field_required || %{}

      on_exit(fn ->
        {:ok, s} = Membership.get_settings()

        Membership.update_settings(s, %{
          member_field_visibility: saved_visibility,
          member_field_required: saved_required
        })
      end)

      :ok
    end

    test "can read settings" do
      # Settings should be a singleton resource
      assert {:ok, _settings} = Membership.get_settings()
    end

    test "settings have club_name attribute" do
      {:ok, settings} = Membership.get_settings()
      assert Map.has_key?(settings, :club_name)
    end

    test "can update club_name" do
      {:ok, settings} = Membership.get_settings()

      assert {:ok, updated_settings} =
               Membership.update_settings(settings, %{club_name: "New Club Name"})

      assert updated_settings.club_name == "New Club Name"
    end

    test "club_name is required" do
      {:ok, settings} = Membership.get_settings()

      assert {:error, %Ash.Error.Invalid{errors: errors}} =
               Membership.update_settings(settings, %{club_name: nil})

      assert error_message(errors, :club_name) =~ "must be present"
    end

    test "club_name cannot be empty" do
      {:ok, settings} = Membership.get_settings()

      assert {:error, %Ash.Error.Invalid{errors: errors}} =
               Membership.update_settings(settings, %{club_name: ""})

      assert error_message(errors, :club_name) =~ "must be present"
    end

    test "can update and read member_field_required" do
      {:ok, settings} = Membership.get_settings()

      required_config = %{"first_name" => true, "last_name" => true}

      assert {:ok, updated} =
               Membership.update_settings(settings, %{member_field_required: required_config})

      assert updated.member_field_required["first_name"] == true
      assert updated.member_field_required["last_name"] == true
    end

    test "member_field_required rejects invalid keys" do
      {:ok, settings} = Membership.get_settings()

      assert {:error, %Ash.Error.Invalid{errors: errors}} =
               Membership.update_settings(settings, %{
                 member_field_required: %{"invalid_field" => true}
               })

      assert error_message(errors, :member_field_required) =~ "Invalid member field"
    end

    test "member_field_required rejects non-boolean values" do
      {:ok, settings} = Membership.get_settings()

      assert {:error, %Ash.Error.Invalid{errors: errors}} =
               Membership.update_settings(settings, %{
                 member_field_required: %{"first_name" => "yes"}
               })

      assert error_message(errors, :member_field_required) =~ "must be booleans"
    end

    test "update_single_member_field updates both visibility and required" do
      {:ok, settings} = Membership.get_settings()

      assert {:ok, updated} =
               Membership.update_single_member_field(settings,
                 field: "first_name",
                 show_in_overview: true,
                 required: true
               )

      assert updated.member_field_visibility["first_name"] == true
      assert updated.member_field_required["first_name"] == true

      # Update same field to required: false
      assert {:ok, updated2} =
               Membership.update_single_member_field(updated,
                 field: "first_name",
                 show_in_overview: false,
                 required: false
               )

      assert updated2.member_field_visibility["first_name"] == false
      assert updated2.member_field_required["first_name"] == false
    end
  end

  # Helper function to extract error messages
  defp error_message(errors, field) do
    errors
    |> Enum.filter(fn err -> Map.get(err, :field) == field end)
    |> Enum.map(&Map.get(&1, :message, ""))
    |> List.first() || ""
  end
end
