<?php

namespace Drupal\eb\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\eb\Entity\EbLogInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Controller for EbLog operations.
 */
class EbLogController extends ControllerBase {

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected Connection $database;

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

  /**
   * Constructs an EbLogController.
   *
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
   *   The date formatter service.
   */
  public function __construct(
    Connection $database,
    DateFormatterInterface $date_formatter,
  ) {
    $this->database = $database;
    $this->dateFormatter = $date_formatter;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    // @phpstan-ignore new.static
    return new static(
      $container->get('database'),
      $container->get('date.formatter'),
    );
  }

  /**
   * Displays watchdog logs for an EbLog entry.
   *
   * @param \Drupal\eb\Entity\EbLogInterface $eb_log
   *   The EbLog entity.
   *
   * @return array<string, mixed>
   *   Render array.
   */
  public function showOperations(EbLogInterface $eb_log): array {
    $build = [];

    // Show log summary.
    $build['summary'] = [
      '#type' => 'details',
      '#title' => $this->t('Log Summary'),
      '#open' => TRUE,
    ];

    $build['summary']['info'] = [
      '#theme' => 'item_list',
      '#items' => [
        $this->t('<strong>Label:</strong> @label', ['@label' => $eb_log->label()]),
        $this->t('<strong>Action:</strong> @action', ['@action' => $eb_log->getAction()]),
        $this->t('<strong>Status:</strong> @status', ['@status' => $eb_log->getStatus()]),
        $this->t('<strong>Operations:</strong> @success/@total', [
          '@success' => $eb_log->getSuccessCount(),
          '@total' => $eb_log->getOperationCount(),
        ]),
        $this->t('<strong>Started:</strong> @time', [
          '@time' => $eb_log->getStarted() ?
          $this->dateFormatter->format($eb_log->getStarted(), 'medium') :
          $this->t('N/A'),
        ]),
        $this->t('<strong>Completed:</strong> @time', [
          '@time' => $eb_log->getCompleted() ?
          $this->dateFormatter->format($eb_log->getCompleted(), 'medium') :
          $this->t('Not completed'),
        ]),
      ],
    ];

    // Check if dblog module is enabled.
    if (!$this->moduleHandler()->moduleExists('dblog')) {
      $build['warning'] = [
        '#type' => 'container',
        '#attributes' => ['class' => ['messages', 'messages--warning']],
        'message' => [
          '#markup' => $this->t('The Database Logging module is not enabled. Operation details are not available.'),
        ],
      ];
      return $build;
    }

    // Query watchdog for eb logs in this time window.
    $started = $eb_log->getStarted();
    $completed = $eb_log->getCompleted() ?? time();

    if ($started === NULL) {
      $build['empty'] = [
        '#markup' => $this->t('No start time recorded for this log entry.'),
      ];
      return $build;
    }

    $query = $this->database->select('watchdog', 'w')
      ->fields('w', ['wid', 'type', 'message', 'variables', 'severity', 'timestamp'])
      ->condition('type', 'eb')
      ->condition('timestamp', $started, '>=')
      ->condition('timestamp', $completed, '<=')
      ->orderBy('timestamp', 'ASC')
      ->orderBy('wid', 'ASC');

    $results = $query->execute()->fetchAll();

    if (empty($results)) {
      $build['operations'] = [
        '#type' => 'details',
        '#title' => $this->t('Operation Details'),
        '#open' => TRUE,
      ];
      $build['operations']['empty'] = [
        '#markup' => $this->t('No operation logs found for this action. Watchdog logs may have been purged.'),
      ];
      return $build;
    }

    // Build operations container.
    $build['operations'] = [
      '#type' => 'details',
      '#title' => $this->t('Operation Details (@count)', ['@count' => count($results)]),
      '#open' => TRUE,
    ];

    // Format each operation as a fieldset with collapsible data.
    $index = 0;
    foreach ($results as $record) {
      $index++;
      $variables = [];
      if (!empty($record->variables)) {
        $variables = @unserialize($record->variables, ['allowed_classes' => FALSE]);
        if ($variables === FALSE) {
          $variables = [];
        }
      }

      $message = $this->formatPlaceholders($record->message, $variables);
      $severity = $this->getSeverityLabel((int) $record->severity);
      $timestamp = $this->dateFormatter->format((int) $record->timestamp, 'short');

      // Build fieldset for this operation.
      $build['operations']['op_' . $index] = [
        '#type' => 'details',
        '#title' => $this->t('@index. @message', [
          '@index' => $index,
          '@message' => $message,
        ]),
        '#open' => FALSE,
        '#attributes' => [
          'class' => ['eb-log-operation', 'eb-log-severity-' . strtolower($severity)],
        ],
      ];

      // Operation metadata.
      $build['operations']['op_' . $index]['meta'] = [
        '#theme' => 'item_list',
        '#items' => [
          $this->t('<strong>Time:</strong> @time', ['@time' => $timestamp]),
          $this->t('<strong>Severity:</strong> @severity', ['@severity' => $severity]),
        ],
      ];

      // Show operation data if available (stored as @data in variables).
      if (!empty($variables['@data'])) {
        $build['operations']['op_' . $index]['data'] = [
          '#type' => 'details',
          '#title' => $this->t('Operation Data'),
          '#open' => FALSE,
        ];
        $build['operations']['op_' . $index]['data']['content'] = [
          '#type' => 'html_tag',
          '#tag' => 'pre',
          '#value' => $variables['@data'],
          '#attributes' => ['class' => ['eb-log-operation-data']],
        ];
      }
    }

    return $build;
  }

  /**
   * Title callback for the show operations page.
   *
   * @param \Drupal\eb\Entity\EbLogInterface $eb_log
   *   The EbLog entity.
   *
   * @return string
   *   The page title.
   */
  public function showOperationsTitle(EbLogInterface $eb_log): string {
    return (string) $this->t('Log: @label', ['@label' => $eb_log->label()]);
  }

  /**
   * Formats a watchdog message with placeholder values.
   *
   * @param string $message
   *   The message template with placeholders.
   * @param array<string, mixed> $variables
   *   The placeholder values.
   *
   * @return string
   *   The formatted message.
   */
  protected function formatPlaceholders(string $message, array $variables): string {
    if (empty($variables)) {
      return $message;
    }

    // Replace placeholders like @field, %type, :link.
    foreach ($variables as $key => $value) {
      if (is_string($value) || is_numeric($value)) {
        $message = str_replace($key, (string) $value, $message);
      }
    }

    return $message;
  }

  /**
   * Gets a human-readable severity label.
   *
   * @param int $severity
   *   The RFC 5424 severity level.
   *
   * @return string
   *   The severity label.
   */
  protected function getSeverityLabel(int $severity): string {
    $labels = [
      0 => 'Emergency',
      1 => 'Alert',
      2 => 'Critical',
      3 => 'Error',
      4 => 'Warning',
      5 => 'Notice',
      6 => 'Info',
      7 => 'Debug',
    ];

    return $labels[$severity] ?? 'Unknown';
  }

}
