<?php

declare(strict_types=1);

namespace Drupal\native_observability_otel\Controller;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\native_observability_otel\Service\PrometheusMetricsBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Returns Prometheus-compatible metrics output.
 */
final readonly class PrometheusMetricsController implements ContainerInjectionInterface {

  /**
   * Constructs the controller.
   *
   * @param \Drupal\native_observability_otel\Service\PrometheusMetricsBuilder $prometheusMetricsBuilder
   *   The Prometheus metrics builder.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   */
  public function __construct(
    private PrometheusMetricsBuilder $prometheusMetricsBuilder,
    private ConfigFactoryInterface $configFactory,
  ) {
  }

  /**
   * Creates a controller instance from the container.
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   The service container.
   *
   * @return static
   *   The controller instance.
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('native_observability_otel.prometheus_metrics_builder'),
      $container->get('config.factory'),
    );
  }

  /**
   * Renders the Prometheus metrics endpoint.
   *
   * Verifies the bearer token when one is configured. Returns 401 when no
   * Authorization header is present and 403 when the token does not match.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The current request.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   The Prometheus text response or an auth error response.
   */
  public function render(Request $request): Response {
    $configuredToken = (string) $this->configFactory
      ->get('native_observability_otel.settings')
      ->get('prometheus_bearer_token');

    if ($configuredToken !== '') {
      $authHeader = (string) $request->headers->get('Authorization', '');
      $prefix = 'Bearer ';

      if (!str_starts_with($authHeader, $prefix)) {
        return new Response('', Response::HTTP_UNAUTHORIZED);
      }

      $providedToken = substr($authHeader, strlen($prefix));
      if (!hash_equals($configuredToken, $providedToken)) {
        return new Response('', Response::HTTP_FORBIDDEN);
      }
    }

    return new Response(
      $this->prometheusMetricsBuilder->build(),
      Response::HTTP_OK,
      [
        'Content-Type' => 'text/plain; version=0.0.4; charset=utf-8',
      ],
    );
  }

}
