<?php

declare(strict_types=1);

namespace Drupal\native_observability_cache_observer\Service;

use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\native_observability_spans\Service\RequestSummaryEnrichmentProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Builds request-level cache enrichment data for synthetic request spans.
 *
 * The payload returned by this provider is intentionally compact so it can be
 * safely embedded in the span payload without creating excessive overhead.
 */
final class CacheSpanEnrichmentProvider implements RequestSummaryEnrichmentProviderInterface {

  /**
   * Creates a new cache span enrichment provider instance.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   */
  public function __construct(
    private readonly ConfigFactoryInterface $configFactory,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  public function buildRequestSummaryPayload(Request $request, Response $response): array {
    $config = $this->configFactory->get('native_observability_cache_observer.settings');

    if (!(bool) $config->get('capture_enabled')) {
      return [];
    }

    $cache = [];

    if ((bool) $config->get('capture_response_headers')) {
      $pageCacheStatus = strtoupper(trim((string) $response->headers->get('X-Drupal-Cache', '')));
      $dynamicPageCacheStatus = strtoupper(trim((string) $response->headers->get('X-Drupal-Dynamic-Cache', '')));

      if ($pageCacheStatus !== '') {
        $cache['page_cache_status'] = $pageCacheStatus;
      }

      if ($dynamicPageCacheStatus !== '') {
        $cache['dynamic_page_cache_status'] = $dynamicPageCacheStatus;
      }
    }

    if ((bool) $config->get('capture_response_cacheability') && $response instanceof CacheableResponseInterface) {
      $metadata = $response->getCacheableMetadata();
      $tags = array_values($metadata->getCacheTags());
      $contexts = array_values($metadata->getCacheContexts());
      $maxAge = $metadata->getCacheMaxAge();

      $cache['cacheability_status'] = $this->deriveCacheabilityStatus($tags, $contexts, $maxAge);
      $cache['tags_count'] = count($tags);
      $cache['contexts_count'] = count($contexts);
      $cache['max_age'] = $maxAge;
    }

    if ($cache === []) {
      return [];
    }

    return [
      'cache' => $cache,
    ];
  }

  /**
   * Derives a compact cacheability status string.
   *
   * @param array $tags
   *   The cache tags.
   * @param array $contexts
   *   The cache contexts.
   * @param int $maxAge
   *   The cache max-age.
   *
   * @return string
   *   The derived cacheability status.
   */
  private function deriveCacheabilityStatus(array $tags, array $contexts, int $maxAge): string {
    if ($maxAge === 0) {
      return 'UNCACHEABLE';
    }

    if ($maxAge > 0 || $maxAge === -1 || $tags !== [] || $contexts !== []) {
      return 'CACHEABLE';
    }

    return 'UNKNOWN';
  }

}
