defmodule MicrowavepropWeb.MetricsPlugTest do
  @moduledoc """
  MetricsPlug mounts as a `forward "/metrics"` in the router, with an
  optional bearer-token gate read from `Application.get_env/2`. These
  tests exercise both the open and gated paths end-to-end.
  """
  use MicrowavepropWeb.ConnCase, async: false

  setup do
    previous = Application.get_env(:microwaveprop, :prometheus_auth_token)
    on_exit(fn -> Application.put_env(:microwaveprop, :prometheus_auth_token, previous) end)
    :ok
  end

  describe "GET /metrics (no token configured)" do
    test "returns 200 with Prometheus text-exposition body", %{conn: conn} do
      Application.put_env(:microwaveprop, :prometheus_auth_token, nil)

      conn = get(conn, ~p"/metrics")

      assert conn.status == 200
      assert [ctype] = get_resp_header(conn, "content-type")
      assert ctype =~ "text/plain"
      # PromEx's text body starts with '# HELP ...' or '# TYPE ...' metrics
      # metadata lines. Exact metrics depend on what's registered, but
      # any non-empty Prometheus body contains at least one '#' comment.
      assert conn.resp_body =~ "#"
    end

    test "blank-string token behaves the same as an unset token", %{conn: conn} do
      Application.put_env(:microwaveprop, :prometheus_auth_token, "")

      conn = get(conn, ~p"/metrics")
      assert conn.status == 200
    end
  end

  describe "GET /metrics (bearer-token gated)" do
    setup do
      Application.put_env(:microwaveprop, :prometheus_auth_token, "s3cret-token")
      :ok
    end

    test "401s without an Authorization header", %{conn: conn} do
      conn = get(conn, ~p"/metrics")
      assert conn.status == 401
      assert conn.resp_body == "unauthorized"
      # Standards-compliant www-authenticate challenge.
      assert [challenge] = get_resp_header(conn, "www-authenticate")
      assert challenge =~ ~s(Bearer realm="metrics")
    end

    test "401s when the Authorization header isn't a Bearer scheme", %{conn: conn} do
      conn =
        conn
        |> put_req_header("authorization", "Basic dXNlcjpwYXNz")
        |> get(~p"/metrics")

      assert conn.status == 401
    end

    test "401s on a wrong bearer token", %{conn: conn} do
      conn =
        conn
        |> put_req_header("authorization", "Bearer wrong-token")
        |> get(~p"/metrics")

      assert conn.status == 401
    end

    test "200s and serves the body when the bearer token matches", %{conn: conn} do
      conn =
        conn
        |> put_req_header("authorization", "Bearer s3cret-token")
        |> get(~p"/metrics")

      assert conn.status == 200
      assert conn.resp_body =~ "#"
    end
  end
end
