defmodule Mv.Secrets do
  @moduledoc """
  Secret provider for AshAuthentication.

  ## Purpose
  Provides runtime configuration secrets for Ash Authentication strategies,
  particularly for OIDC (Rauthy) authentication.

  ## Configuration Source
  Secrets are read via `Mv.Config` which prefers environment variables and
  falls back to Settings from the database:
  - OIDC_CLIENT_ID / settings.oidc_client_id
  - OIDC_CLIENT_SECRET / settings.oidc_client_secret
  - OIDC_BASE_URL / settings.oidc_base_url
  - OIDC_REDIRECT_URI / settings.oidc_redirect_uri

  When a value is nil, returns `{:error, MissingSecret}` so that AshAuthentication
  does not crash (e.g. URI.new(nil)) and can redirect to sign-in with an error.
  """
  use AshAuthentication.Secret

  alias AshAuthentication.Errors.MissingSecret

  def secret_for(
        [:authentication, :strategies, :oidc, :client_id],
        resource,
        _opts,
        _meth
      ) do
    secret_or_error(Mv.Config.oidc_client_id(), resource, :client_id)
  end

  def secret_for(
        [:authentication, :strategies, :oidc, :redirect_uri],
        resource,
        _opts,
        _meth
      ) do
    secret_or_error(Mv.Config.oidc_redirect_uri(), resource, :redirect_uri)
  end

  def secret_for(
        [:authentication, :strategies, :oidc, :client_secret],
        resource,
        _opts,
        _meth
      ) do
    secret_or_error(Mv.Config.oidc_client_secret(), resource, :client_secret)
  end

  def secret_for(
        [:authentication, :strategies, :oidc, :base_url],
        resource,
        _opts,
        _meth
      ) do
    secret_or_error(Mv.Config.oidc_base_url(), resource, :base_url)
  end

  defp secret_or_error(nil, resource, key) do
    path = [:authentication, :strategies, :oidc, key]
    {:error, MissingSecret.exception(path: path, resource: resource)}
  end

  defp secret_or_error(value, resource, key) when is_binary(value) do
    if String.trim(value) == "" do
      secret_or_error(nil, resource, key)
    else
      {:ok, value}
    end
  end
end
