<?php

declare(strict_types=1);

namespace Drupal\native_observability_dashboard\Controller;

use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\native_observability_dashboard\Service\DashboardTimeRangeResolver;
use Drupal\native_observability_dashboard\Service\TraceMetricsReader;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Provides export and maintenance operations for the explorer.
 */
final class TechnicalInsightsController extends ControllerBase {

  /**
   * Creates a new technical insights controller instance.
   *
   * @param \Drupal\native_observability_dashboard\Service\TraceMetricsReader $traceMetricsReader
   *   The trace metrics reader service.
   * @param \Drupal\native_observability_dashboard\Service\DashboardTimeRangeResolver $rangeResolver
   *   The dashboard time range resolver.
   * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cacheTagsInvalidator
   *   The cache tags invalidator service.
   */
  public function __construct(
    private readonly TraceMetricsReader $traceMetricsReader,
    private readonly DashboardTimeRangeResolver $rangeResolver,
    private readonly CacheTagsInvalidatorInterface $cacheTagsInvalidator,
  ) {
  }

  /**
   * Exports a dataset as CSV.
   *
   * @param string $dataset
   *   The dataset key.
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The current request.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   The CSV response.
   */
  public function export(string $dataset, Request $request): Response {
    $range = $this->rangeResolver->resolve();
    $rows = $this->resolveDatasetRows($dataset, $range);

    if (!$rows) {
      return new Response('', 204);
    }

    $exportColumns = $this->resolveExportColumns($dataset);
    $csv = implode(',', array_keys($exportColumns)) . "\n";

    foreach ($rows as $row) {
      $line = [];

      foreach ($exportColumns as $sourceKey) {
        $value = $row[$sourceKey] ?? '';
        $value = str_replace('"', '""', (string) $value);
        $line[] = "\"{$value}\"";
      }

      $csv .= implode(',', $line) . "\n";
    }

    return new Response(
      $csv,
      200,
      [
        'Content-Type' => 'text/csv; charset=UTF-8',
        'Content-Disposition' => 'attachment; filename="native-observability-' . $dataset . '-' . $range->getKey() . '.csv"',
      ],
    );
  }

  /**
   * Flushes only dashboard-level cache for the selected dataset.
   *
   * IMPORTANT:
   * This operation never deletes raw traces or raw spans.
   *
   * @param string $dataset
   *   The dataset key.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response.
   */
  public function flush(string $dataset): JsonResponse {
    $normalizedDataset = $this->normalizeDatasetKey($dataset);

    $this->cacheTagsInvalidator->invalidateTags([
      'native_observability_dashboard',
      'native_observability_dashboard:technical_insights',
      'native_observability_dashboard:' . $normalizedDataset,
    ]);

    return new JsonResponse([
      'status' => 'ok',
      'message' => 'Technical Insights cache invalidated successfully.',
      'dataset' => $normalizedDataset,
    ]);
  }

  /**
   * Resolves dataset rows from the current selection.
   *
   * @param string $dataset
   *   The raw dataset key.
   * @param mixed $range
   *   The selected dashboard time range value object.
   *
   * @return array
   *   The resolved dataset rows.
   */
  private function resolveDatasetRows(string $dataset, mixed $range): array {
    return match ($this->normalizeDatasetKey($dataset)) {
      'slow_endpoints' => $this->traceMetricsReader->getSlowEndpointDataset($range),
      'ajax_endpoints' => $this->traceMetricsReader->getAjaxEndpointDataset($range),
      'external_requests' => $this->traceMetricsReader->getExternalRequestDataset($range),
      default => [],
    };
  }

  /**
   * Resolves export columns for a dataset.
   *
   * @param string $dataset
   *   The dataset key.
   *
   * @return array
   *   The export columns map.
   */
  private function resolveExportColumns(string $dataset): array {
    return match ($this->normalizeDatasetKey($dataset)) {
      'external_requests' => [
        'target' => 'target',
        'method' => 'method',
        'calls' => 'request_count',
        'avg' => 'avg_duration',
        'errors' => 'error_count',
      ],
      default => [
        'path' => 'path',
        'route' => 'route_name',
        'calls' => 'request_count',
        'avg' => 'avg_duration',
        'errors' => 'error_count',
      ],
    };
  }

  /**
   * Normalizes legacy and current dataset keys.
   *
   * @param string $dataset
   *   The raw dataset key.
   *
   * @return string
   *   The normalized dataset key.
   */
  private function normalizeDatasetKey(string $dataset): string {
    return match ($dataset) {
      'slow' => 'slow_endpoints',
      'ajax' => 'ajax_endpoints',
      'external' => 'external_requests',
      default => $dataset,
    };
  }

}
