defmodule Towerops.SettingsTest do
  use Towerops.DataCase

  alias Towerops.Settings
  alias Towerops.Settings.ApplicationSetting

  describe "get_setting/1" do
    test "returns parsed value for existing setting" do
      # The migration already created the global_default_cloud_poller_id setting
      assert Settings.get_setting("global_default_cloud_poller_id") == nil
    end

    test "returns nil for non-existent setting" do
      assert Settings.get_setting("nonexistent_key") == nil
    end

    test "parses string values correctly" do
      {:ok, _setting} = create_setting("test_string", "hello", "string")
      assert Settings.get_setting("test_string") == "hello"
    end

    test "parses integer values correctly" do
      {:ok, _setting} = create_setting("test_integer", "42", "integer")
      assert Settings.get_setting("test_integer") == 42
    end

    test "parses boolean values correctly" do
      {:ok, _setting} = create_setting("test_bool_true", "true", "boolean")
      {:ok, _setting} = create_setting("test_bool_false", "false", "boolean")
      {:ok, _setting} = create_setting("test_bool_one", "1", "boolean")
      {:ok, _setting} = create_setting("test_bool_zero", "0", "boolean")

      assert Settings.get_setting("test_bool_true") == true
      assert Settings.get_setting("test_bool_false") == false
      assert Settings.get_setting("test_bool_one") == true
      assert Settings.get_setting("test_bool_zero") == false
    end

    test "parses json values correctly" do
      {:ok, _setting} = create_setting("test_json", ~s({"key": "value"}), "json")
      assert Settings.get_setting("test_json") == %{"key" => "value"}
    end

    test "returns nil for invalid integer" do
      {:ok, _setting} = create_setting("test_invalid_int", "not_a_number", "integer")
      assert Settings.get_setting("test_invalid_int") == nil
    end

    test "returns nil for invalid json" do
      {:ok, _setting} = create_setting("test_invalid_json", "not json", "json")
      assert Settings.get_setting("test_invalid_json") == nil
    end
  end

  describe "get_setting_record/1" do
    test "returns the raw ApplicationSetting record" do
      record = Settings.get_setting_record("global_default_cloud_poller_id")
      assert %ApplicationSetting{} = record
      assert record.key == "global_default_cloud_poller_id"
      assert record.value_type == "uuid"
    end

    test "returns nil for non-existent setting" do
      assert Settings.get_setting_record("nonexistent") == nil
    end
  end

  describe "update_setting/2" do
    test "updates an existing setting value" do
      agent_token_id = Ecto.UUID.generate()
      {:ok, updated} = Settings.update_setting("global_default_cloud_poller_id", agent_token_id)

      assert updated.value == agent_token_id
      assert Settings.get_setting("global_default_cloud_poller_id") == agent_token_id
    end

    test "updates setting to nil" do
      agent_token_id = Ecto.UUID.generate()
      {:ok, _} = Settings.update_setting("global_default_cloud_poller_id", agent_token_id)
      {:ok, updated} = Settings.update_setting("global_default_cloud_poller_id", nil)

      assert updated.value == nil
      assert Settings.get_setting("global_default_cloud_poller_id") == nil
    end

    test "returns error for non-existent setting" do
      assert {:error, :setting_not_found} =
               Settings.update_setting("nonexistent_key", "value")
    end

    test "converts non-string values to strings" do
      {:ok, _setting} = create_setting("test_number", "0", "integer")
      {:ok, updated} = Settings.update_setting("test_number", 123)

      assert updated.value == "123"
      assert Settings.get_setting("test_number") == 123
    end
  end

  describe "get_global_default_cloud_poller/0" do
    test "returns nil when not configured" do
      assert Settings.get_global_default_cloud_poller() == nil
    end

    test "returns agent token ID when configured" do
      agent_token_id = Ecto.UUID.generate()
      {:ok, _} = Settings.set_global_default_cloud_poller(agent_token_id)

      assert Settings.get_global_default_cloud_poller() == agent_token_id
    end
  end

  describe "set_global_default_cloud_poller/1" do
    test "sets the global default cloud poller" do
      agent_token_id = Ecto.UUID.generate()
      {:ok, setting} = Settings.set_global_default_cloud_poller(agent_token_id)

      assert setting.value == agent_token_id
      assert Settings.get_global_default_cloud_poller() == agent_token_id
    end

    test "clears the global default cloud poller when set to nil" do
      agent_token_id = Ecto.UUID.generate()
      {:ok, _} = Settings.set_global_default_cloud_poller(agent_token_id)
      {:ok, setting} = Settings.set_global_default_cloud_poller(nil)

      assert setting.value == nil
      assert Settings.get_global_default_cloud_poller() == nil
    end
  end

  describe "list_all_settings/0" do
    test "returns all application settings" do
      settings = Settings.list_all_settings()

      assert is_list(settings)
      refute Enum.empty?(settings)
      assert Enum.any?(settings, &(&1.key == "global_default_cloud_poller_id"))
    end
  end

  # Helper function to create test settings
  defp create_setting(key, value, value_type) do
    %ApplicationSetting{}
    |> ApplicationSetting.changeset(%{
      key: key,
      value: value,
      value_type: value_type
    })
    |> Repo.insert()
  end
end
