<?php

declare(strict_types=1);

namespace Drupal\native_observability_metrics\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\native_observability_metrics\Service\RouteMetricsAggregator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\native_observability_metrics\Form\MetricsAggregationRunForm;

/**
 * Builds the Native Observability Metrics Dashboard page.
 */
final class MetricsDashboardController extends ControllerBase {

  /**
   * The route metrics aggregator service.
   *
   * @var \Drupal\native_observability_metrics\Service\RouteMetricsAggregator
   */
  protected RouteMetricsAggregator $routeMetricsAggregator;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected DateFormatterInterface $dateFormatter;

  /**
   * Constructs a new MetricsDashboardController instance.
   *
   * @param \Drupal\native_observability_metrics\Service\RouteMetricsAggregator $route_metrics_aggregator
   *   The route metrics aggregator service.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
   *   The date formatter service.
   * @param \Drupal\Core\Form\FormBuilderInterface $formBuilder
   *   The form builder service.
   */
  public function __construct(
    RouteMetricsAggregator $route_metrics_aggregator,
    DateFormatterInterface $date_formatter,
    FormBuilderInterface $formBuilder,
  ) {
    $this->routeMetricsAggregator = $route_metrics_aggregator;
    $this->dateFormatter = $date_formatter;
    $this->formBuilder = $formBuilder;
  }

  /**
   * Creates an instance of the controller 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_metrics.route_metrics_aggregator'),
      $container->get('date.formatter'),
      $container->get('form_builder'),
    );
  }

  /**
   * Builds the metrics dashboard.
   *
   * @return array
   *   A render array containing the metrics dashboard.
   */
  public function dashboard(): array {
    $metrics = $this->routeMetricsAggregator->getLatestSnapshot();

    $rows = [];
    $window_label = $this->t('No aggregation window available yet.');

    if (!empty($metrics)) {
      $first_row = reset($metrics);

      if (!empty($first_row['window_start']) && !empty($first_row['window_end'])) {
        $window_label = $this->t(
          '@start → @end',
          [
            '@start' => $this->dateFormatter->format((int) $first_row['window_start'], 'short'),
            '@end' => $this->dateFormatter->format((int) $first_row['window_end'], 'short'),
          ]
        );
      }

      foreach ($metrics as $metric) {
        $rows[] = [
          'route_key' => [
            'data' => [
              '#markup' => $this->buildRouteLabel($metric),
            ],
          ],
          'request_count' => [
            'data' => (string) ($metric['request_count'] ?? 0),
          ],
          'throughput_per_minute' => [
            'data' => (string) ($metric['throughput_per_minute'] ?? '0.00'),
          ],
          'avg_duration_ms' => [
            'data' => (string) ($metric['avg_duration_ms'] ?? 0),
          ],
          'p95_duration_ms' => [
            'data' => (string) ($metric['p95_duration_ms'] ?? 0),
          ],
          'p99_duration_ms' => [
            'data' => (string) ($metric['p99_duration_ms'] ?? 0),
          ],
        ];
      }
    }

    return [
      '#type' => 'container',
      '#attributes' => [
        'class' => ['native-observability-metrics-dashboard'],
      ],
      '#attached' => [
        'library' => [
          'native_observability_metrics/dashboard',
        ],
      ],
      'header' => [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-dashboard__header'],
        ],
        'title' => [
          '#markup' => '<h2>' . $this->t('Native Observability Metrics Dashboard') . '</h2>',
        ],
        'description' => [
          '#markup' => '<p>' . $this->t('This dashboard displays aggregated route performance metrics derived from Native Observability trace data.') . '</p>',
        ],
        'window' => [
          '#markup' => '<p><strong>' . $this->t('Latest aggregation window:') . '</strong> ' . $window_label . '</p>',
        ],
      ],
      'aggregation_actions' => [
        '#type' => 'details',
        '#title' => $this->t('Manual aggregation'),
        '#open' => FALSE,
        '#attributes' => [
          'class' => ['native-observability-metrics-dashboard__actions'],
        ],
        'description' => [
          '#markup' => '<p>' . $this->t('Aggregate the latest completed metrics window. Requests collected in the current open window will be included only after that window has finished.') . '</p>',
        ],
        'run_form' => $this->formBuilder->getForm(MetricsAggregationRunForm::class),
      ],
      'summary_cards' => $this->buildSummaryCards($metrics),
      'requests_chart' => $this->buildRequestsChart($metrics),
      'avg_duration_chart' => $this->buildAvgDurationChart($metrics),
      'table' => [
        '#type' => 'table',
        '#header' => [
          $this->t('Route'),
          $this->t('Requests'),
          $this->t('Throughput / min'),
          $this->t('Avg duration (ms)'),
          $this->t('P95 (ms)'),
          $this->t('P99 (ms)'),
        ],
        '#rows' => $rows,
        '#empty' => $this->t('No metrics are available yet. Run cron or trigger a manual aggregation after generating trace traffic.'),
        '#attributes' => [
          'class' => ['native-observability-metrics-dashboard__table'],
        ],
      ],
    ];
  }

  /**
   * Builds summary cards for the latest metrics snapshot.
   *
   * @param array $metrics
   *   Latest aggregated metrics snapshot.
   *
   * @return array
   *   Render array.
   */
  private function buildSummaryCards(array $metrics): array {
    if (empty($metrics)) {
      return [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-summary'],
        ],
      ];
    }

    $total_requests = 0;
    $weighted_duration_sum = 0;
    $max_p95 = 0;
    $max_p99 = 0;
    $max_throughput = 0.0;

    foreach ($metrics as $metric) {
      $request_count = (int) ($metric['request_count'] ?? 0);
      $avg_duration = (int) ($metric['avg_duration_ms'] ?? 0);
      $p95 = (int) ($metric['p95_duration_ms'] ?? 0);
      $p99 = (int) ($metric['p99_duration_ms'] ?? 0);
      $throughput = (float) ($metric['throughput_per_minute'] ?? 0);

      $total_requests += $request_count;
      $weighted_duration_sum += ($avg_duration * $request_count);
      $max_p95 = max($max_p95, $p95);
      $max_p99 = max($max_p99, $p99);
      $max_throughput = max($max_throughput, $throughput);
    }

    $overall_avg_duration = $total_requests > 0
      ? (int) round($weighted_duration_sum / $total_requests)
      : 0;

    $cards = [
      [
        'label' => $this->t('Total requests'),
        'value' => (string) $total_requests,
      ],
      [
        'label' => $this->t('Avg duration'),
        'value' => $overall_avg_duration . ' ms',
      ],
      [
        'label' => $this->t('Max P95'),
        'value' => $max_p95 . ' ms',
      ],
      [
        'label' => $this->t('Max P99'),
        'value' => $max_p99 . ' ms',
      ],
      [
        'label' => $this->t('Peak throughput'),
        'value' => number_format($max_throughput, 2) . ' / min',
      ],
    ];

    $build = [
      '#type' => 'container',
      '#attributes' => [
        'class' => ['native-observability-metrics-summary'],
      ],
    ];

    foreach ($cards as $delta => $card) {
      $build['card_' . $delta] = [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-summary__card'],
        ],
        'label' => [
          '#markup' => '<div class="native-observability-metrics-summary__label">' . $card['label'] . '</div>',
        ],
        'value' => [
          '#markup' => '<div class="native-observability-metrics-summary__value">' . $card['value'] . '</div>',
        ],
      ];
    }

    return $build;
  }

  /**
   * Builds a simple bar chart for requests by route.
   *
   * @param array $metrics
   *   Latest aggregated metrics snapshot.
   *
   * @return array
   *   Render array.
   */
  private function buildRequestsChart(array $metrics): array {
    if (empty($metrics)) {
      return [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-chart'],
        ],
      ];
    }

    $max_requests = 0;
    foreach ($metrics as $metric) {
      $max_requests = max($max_requests, (int) ($metric['request_count'] ?? 0));
    }

    $build = [
      '#type' => 'container',
      '#attributes' => [
        'class' => ['native-observability-metrics-chart'],
      ],
      'title' => [
        '#markup' => '<h3>' . $this->t('Requests by route') . '</h3>',
      ],
      'description' => [
        '#markup' => '<p>' . $this->t('Visual comparison of aggregated request volume for the latest completed metrics window.') . '</p>',
      ],
      'items' => [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-chart__items'],
        ],
      ],
    ];

    foreach ($metrics as $delta => $metric) {
      $request_count = (int) ($metric['request_count'] ?? 0);
      $bar_width = $max_requests > 0 ? ($request_count / $max_requests) * 100 : 0;
      $route_label = $this->buildRouteLabel($metric);

      $build['items']['item_' . $delta] = [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-chart__item'],
        ],
        'label' => [
          '#markup' => '<div class="native-observability-metrics-chart__label">' . $route_label . '</div>',
        ],
        'bar_wrapper' => [
          '#type' => 'container',
          '#attributes' => [
            'class' => ['native-observability-metrics-chart__bar-wrapper'],
          ],
          'bar' => [
            '#markup' => '<div class="native-observability-metrics-chart__bar" style="width:' . round($bar_width, 2) . '%;"></div>',
          ],
        ],
        'value' => [
          '#markup' => '<div class="native-observability-metrics-chart__value">' . $request_count . '</div>',
        ],
      ];
    }

    return $build;
  }

  /**
   * Builds a simple bar chart for average duration by route.
   *
   * @param array $metrics
   *   Latest aggregated metrics snapshot.
   *
   * @return array
   *   Render array.
   */
  private function buildAvgDurationChart(array $metrics): array {
    if (empty($metrics)) {
      return [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-chart'],
        ],
      ];
    }

    $max_duration = 0;
    foreach ($metrics as $metric) {
      $max_duration = max($max_duration, (int) ($metric['avg_duration_ms'] ?? 0));
    }

    $build = [
      '#type' => 'container',
      '#attributes' => [
        'class' => ['native-observability-metrics-chart'],
      ],
      'title' => [
        '#markup' => '<h3>' . $this->t('Average duration by route') . '</h3>',
      ],
      'description' => [
        '#markup' => '<p>' . $this->t('Visual comparison of average response duration for the latest completed metrics window.') . '</p>',
      ],
      'items' => [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-chart__items'],
        ],
      ],
    ];

    foreach ($metrics as $delta => $metric) {
      $avg_duration = (int) ($metric['avg_duration_ms'] ?? 0);
      $bar_width = $max_duration > 0 ? ($avg_duration / $max_duration) * 100 : 0;
      $route_label = $this->buildRouteLabel($metric);

      $build['items']['item_' . $delta] = [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['native-observability-metrics-chart__item'],
        ],
        'label' => [
          '#markup' => '<div class="native-observability-metrics-chart__label">' . $route_label . '</div>',
        ],
        'bar_wrapper' => [
          '#type' => 'container',
          '#attributes' => [
            'class' => ['native-observability-metrics-chart__bar-wrapper'],
          ],
          'bar' => [
            '#markup' => '<div class="native-observability-metrics-chart__bar native-observability-metrics-chart__bar--latency" style="width:' . round($bar_width, 2) . '%;"></div>',
          ],
        ],
        'value' => [
          '#markup' => '<div class="native-observability-metrics-chart__value">' . $avg_duration . ' ms</div>',
        ],
      ];
    }

    return $build;
  }

  /**
   * Builds the route label markup.
   *
   * @param array $metric
   *   A single metric row.
   *
   * @return string
   *   The route label markup.
   */
  protected function buildRouteLabel(array $metric): string {
    $route_key = (string) ($metric['route_key'] ?? 'unknown');
    $route_name = (string) ($metric['route_name'] ?? '');

    if ($route_name !== '' && $route_name !== $route_key) {
      return '<strong>' . $route_key . '</strong><br><small>' . $route_name . '</small>';
    }

    return '<strong>' . $route_key . '</strong>';
  }

}
