lib/pgflow_dashboard/config.ex

defmodule PgFlowDashboard.Config do
  @moduledoc """
  Configuration validation and management for PgFlowDashboard.

  Uses NimbleOptions to validate configuration options passed to the dashboard router.

  ## Required Options

    * `:repo` - The Ecto repository module to use for database queries.
    * `:pubsub` - The Phoenix.PubSub module for real-time updates.

  ## Optional Options

    * `:refresh_interval` - Polling interval in milliseconds. Default: `5_000`.
    * `:time_zone` - Time zone for displaying timestamps. Default: `"UTC"`.
    * `:default_time_range` - Default time range filter. Default: `:last_24h`.
    * `:max_grid_runs` - Maximum runs to show in history grid. Default: `50`.
    * `:query_timeout` - Database query timeout in milliseconds. Default: `10_000`.
    * `:enable_pubsub` - Whether to enable real-time PubSub updates. Default: `true`.
    * `:cache_ttl` - Cache TTL in milliseconds. Default: `5_000`.

  ## Examples

      config = PgFlowDashboard.Config.validate!(
        repo: MyApp.Repo,
        pubsub: MyApp.PubSub,
        refresh_interval: 10_000
      )

  """

  alias PgFlow.Config.RepoValidator

  @schema [
    repo: [
      type: :atom,
      required: true,
      doc: "The Ecto repository module to use for database queries"
    ],
    pubsub: [
      type: :atom,
      required: true,
      doc: "The Phoenix.PubSub module for real-time updates"
    ],
    refresh_interval: [
      type: :pos_integer,
      default: 5_000,
      doc: "Polling interval in milliseconds for dashboard updates"
    ],
    time_zone: [
      type: :string,
      default: "UTC",
      doc: "Time zone for displaying timestamps"
    ],
    default_time_range: [
      type: {:in, [:last_hour, :last_24h, :last_7d, :last_30d]},
      default: :last_24h,
      doc: "Default time range filter for queries"
    ],
    max_grid_runs: [
      type: :pos_integer,
      default: 50,
      doc: "Maximum number of runs to display in the history grid"
    ],
    query_timeout: [
      type: :pos_integer,
      default: 10_000,
      doc: "Database query timeout in milliseconds"
    ],
    enable_pubsub: [
      type: :boolean,
      default: true,
      doc: "Whether to enable real-time PubSub updates"
    ],
    cache_ttl: [
      type: :pos_integer,
      default: 5_000,
      doc: "Cache TTL in milliseconds for expensive aggregations"
    ]
  ]

  @doc """
  Validates the given configuration options.

  Raises `ArgumentError` if the configuration is invalid.

  ## Examples

      iex> PgFlowDashboard.Config.validate!(repo: MyApp.Repo, pubsub: MyApp.PubSub)
      [repo: MyApp.Repo, pubsub: MyApp.PubSub, ...]

      iex> PgFlowDashboard.Config.validate!(pubsub: MyApp.PubSub)
      ** (ArgumentError) required :repo option not found

  """
  @spec validate!(keyword()) :: keyword()
  def validate!(opts) when is_list(opts) do
    case NimbleOptions.validate(opts, @schema) do
      {:ok, config} ->
        RepoValidator.validate_repo!(config[:repo])
        config

      {:error, error} ->
        raise ArgumentError, "invalid PgFlowDashboard configuration: #{Exception.message(error)}"
    end
  end

  @doc """
  Returns the NimbleOptions schema for PgFlowDashboard configuration.
  """
  @spec schema() :: keyword()
  def schema, do: @schema
end