defmodule Towerops.Settings.ApplicationSetting do
  @moduledoc """
  Application-wide settings schema.

  Stores global configuration values that affect the entire application,
  regardless of organization. Only accessible by superadmins.
  """
  use Ecto.Schema

  import Ecto.Changeset

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "application_settings" do
    field :key, :string
    field :value, :string
    field :value_type, :string, default: "string"
    field :description, :string

    timestamps(type: :utc_datetime)
  end

  @type t :: %__MODULE__{
          id: Ecto.UUID.t(),
          key: String.t(),
          value: String.t() | nil,
          value_type: String.t(),
          description: String.t() | nil,
          inserted_at: DateTime.t(),
          updated_at: DateTime.t()
        }

  @doc false
  def changeset(setting, attrs) do
    setting
    |> cast(attrs, [:key, :value, :value_type, :description])
    |> validate_required([:key, :value_type])
    |> validate_inclusion(:value_type, ["string", "integer", "uuid", "boolean", "json"])
    |> unique_constraint(:key)
  end

  @doc """
  Parses the value field according to value_type.

  ## Examples

      iex> parse_value(%ApplicationSetting{value: "abc-123", value_type: "uuid"})
      "abc-123"

      iex> parse_value(%ApplicationSetting{value: nil, value_type: "uuid"})
      nil
  """
  def parse_value(%__MODULE__{value: nil}), do: nil

  def parse_value(%__MODULE__{value: value, value_type: "string"}), do: value
  def parse_value(%__MODULE__{value: value, value_type: "uuid"}), do: value

  def parse_value(%__MODULE__{value: value, value_type: "integer"}) do
    case Integer.parse(value) do
      {int, _} -> int
      :error -> nil
    end
  end

  def parse_value(%__MODULE__{value: value, value_type: "boolean"}) do
    value in ["true", "1", "yes"]
  end

  def parse_value(%__MODULE__{value: value, value_type: "json"}) do
    case Jason.decode(value) do
      {:ok, decoded} -> decoded
      {:error, _} -> nil
    end
  end
end
