defmodule WhoNeedHelpWeb.WorkerMetricsPlug do
  @moduledoc """
  Internal-only health and Prometheus endpoint for worker-role releases.

  Compose and Kubernetes keep this listener off public ingress. Metrics still
  require the same independent bearer credential as web replicas.
  """

  import Plug.Conn

  alias WhoNeedHelpWeb.MetricsAccess

  @content_type "text/plain; version=0.0.4"

  def init(options), do: options

  def call(%Plug.Conn{method: "GET", path_info: ["healthz", "live"]} = conn, _options) do
    json(conn, :ok, %{status: "ok", node: to_string(Node.self()), role: "worker"})
  end

  def call(%Plug.Conn{method: "GET", path_info: ["healthz", "ready"]} = conn, _options) do
    database_ready? =
      match?({:ok, _}, Ecto.Adapters.SQL.query(WhoNeedHelp.Repo, "SELECT 1", []))

    if database_ready? and is_pid(Oban.whereis(Oban)) do
      json(conn, :ok, %{status: "ready", node: to_string(Node.self()), role: "worker"})
    else
      json(conn, :service_unavailable, %{status: "not_ready", role: "worker"})
    end
  end

  # Sobelow's HTML-oriented SendResp check cannot infer this fixed Prometheus
  # text content type. The response is generated by the metrics registry and
  # is not rendered in an HTML context.
  # sobelow_skip ["XSS.SendResp"]
  def call(%Plug.Conn{method: "GET", path_info: ["metrics"]} = conn, _options) do
    token = Application.get_env(:who_need_help, :metrics_token)

    if MetricsAccess.authorized?(get_req_header(conn, "authorization"), token) do
      body = TelemetryMetricsPrometheus.Core.scrape(:prometheus_metrics)

      conn
      |> put_resp_header("cache-control", "no-store")
      |> put_resp_content_type(@content_type)
      |> send_resp(:ok, body)
    else
      conn
      |> put_resp_header("cache-control", "no-store")
      |> put_resp_header("www-authenticate", "Bearer")
      |> send_resp(:unauthorized, "Unauthorized\n")
    end
  end

  def call(conn, _options), do: send_resp(conn, :not_found, "Not found\n")

  def child_spec(_options) do
    endpoint_config = Application.fetch_env!(:who_need_help, WhoNeedHelpWeb.Endpoint)
    port = endpoint_config |> Keyword.fetch!(:http) |> Keyword.fetch!(:port)

    Bandit.child_spec(
      plug: __MODULE__,
      scheme: :http,
      ip: {0, 0, 0, 0},
      port: port,
      startup_log: false
    )
    |> Supervisor.child_spec(id: __MODULE__)
  end

  defp json(conn, status, body) do
    conn
    |> put_resp_header("cache-control", "no-store")
    |> put_resp_content_type("application/json")
    |> send_resp(status, Jason.encode!(body))
  end
end
