defmodule MicrowavepropWeb.MetricsPlug do
  @moduledoc """
  Serves PromEx metrics at `/metrics`. Optionally gated by a bearer
  token via `config :microwaveprop, :prometheus_auth_token`, sourced
  from the `PROMETHEUS_AUTH_TOKEN` env var in `runtime.exs`.
  """

  @behaviour Plug

  import Plug.Conn

  @impl true
  def init(opts), do: opts

  @impl true
  def call(conn, _opts) do
    case authorized?(conn) do
      :ok ->
        body = PromEx.get_metrics(Microwaveprop.PromEx)

        conn
        |> put_resp_content_type("text/plain; version=0.0.4")
        |> send_resp(200, body)
        |> halt()

      :denied ->
        conn
        |> put_resp_header("www-authenticate", ~s(Bearer realm="metrics"))
        |> send_resp(401, "unauthorized")
        |> halt()
    end
  end

  defp authorized?(conn) do
    case Application.get_env(:microwaveprop, :prometheus_auth_token) do
      token when is_binary(token) and token != "" ->
        check_token(conn, token)

      _ ->
        :ok
    end
  end

  defp check_token(conn, expected) do
    conn
    |> get_req_header("authorization")
    |> List.first()
    |> case do
      "Bearer " <> token ->
        if Plug.Crypto.secure_compare(token, expected), do: :ok, else: :denied

      _ ->
        :denied
    end
  end
end
