defmodule Towerops.Settings do
  @moduledoc """
  The Settings context for application-wide configuration.

  Provides functions for reading and updating global settings that affect
  the entire application. Only accessible by superadmins.
  """

  import Ecto.Query, warn: false

  alias Towerops.Repo
  alias Towerops.Settings.ApplicationSetting

  @doc """
  Gets a setting by key and returns the parsed value.

  Returns nil if the setting doesn't exist or has a nil value.

  ## Examples

      iex> get_setting("global_default_cloud_poller_id")
      "abc-123-uuid"

      iex> get_setting("nonexistent_key")
      nil
  """
  def get_setting(key) when is_binary(key) do
    case Repo.get_by(ApplicationSetting, key: key) do
      nil -> nil
      setting -> ApplicationSetting.parse_value(setting)
    end
  end

  @doc """
  Gets the raw ApplicationSetting record by key.

  ## Examples

      iex> get_setting_record("global_default_cloud_poller_id")
      %ApplicationSetting{key: "global_default_cloud_poller_id", value: "abc-123"}
  """
  def get_setting_record(key) when is_binary(key) do
    Repo.get_by(ApplicationSetting, key: key)
  end

  @doc """
  Updates a setting value.

  ## Examples

      iex> update_setting("global_default_cloud_poller_id", "new-uuid")
      {:ok, %ApplicationSetting{}}

      iex> update_setting("global_default_cloud_poller_id", nil)
      {:ok, %ApplicationSetting{value: nil}}
  """
  def update_setting(key, value) when is_binary(key) do
    case get_setting_record(key) do
      nil ->
        {:error, :setting_not_found}

      setting ->
        setting
        |> ApplicationSetting.changeset(%{value: to_string_or_nil(value)})
        |> Repo.update()
    end
  end

  @doc """
  Gets the global default cloud poller agent token ID.

  Returns nil if not configured.

  ## Examples

      iex> get_global_default_cloud_poller()
      "abc-123-uuid"

      iex> get_global_default_cloud_poller()
      nil
  """
  def get_global_default_cloud_poller do
    get_setting("global_default_cloud_poller_id")
  end

  @doc """
  Sets the global default cloud poller agent token ID.

  ## Examples

      iex> set_global_default_cloud_poller("agent-token-uuid")
      {:ok, %ApplicationSetting{}}

      iex> set_global_default_cloud_poller(nil)
      {:ok, %ApplicationSetting{value: nil}}
  """
  def set_global_default_cloud_poller(agent_token_id) do
    update_setting("global_default_cloud_poller_id", agent_token_id)
  end

  @doc """
  Lists all application settings.

  ## Examples

      iex> list_all_settings()
      [%ApplicationSetting{}, ...]
  """
  def list_all_settings do
    Repo.all(ApplicationSetting)
  end

  # Private helpers

  defp to_string_or_nil(nil), do: nil
  defp to_string_or_nil(value), do: to_string(value)
end
