<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media_ui\Controller;

use Drupal\Component\Utility\Unicode;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Pager\PagerManagerInterface;
use Drupal\ffmpeg_media\Service\DeadLetterStorageInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * Controller for browsing dead-letter conversion failures.
 */
final class DeadLetterController extends ControllerBase {

  /**
   * Number of dead-letter entries shown per page.
   */
  private const int PAGE_LIMIT = 25;

  /**
   * Constructs a DeadLetterController object.
   *
   * @param \Drupal\ffmpeg_media\Service\DeadLetterStorageInterface $deadLetterStorage
   *   Dead-letter storage service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $mediaEntityTypeManager
   *   Entity type manager.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter
   *   Date formatter.
   * @param \Drupal\Core\Pager\PagerManagerInterface $pagerManager
   *   Pager manager.
   */
  public function __construct(
    #[Autowire(service: DeadLetterStorageInterface::class)]
    private readonly DeadLetterStorageInterface $deadLetterStorage,
    #[Autowire(service: 'entity_type.manager')]
    private readonly EntityTypeManagerInterface $mediaEntityTypeManager,
    #[Autowire(service: 'date.formatter')]
    private readonly DateFormatterInterface $dateFormatter,
    #[Autowire(service: 'pager.manager')]
    private readonly PagerManagerInterface $pagerManager,
  ) {}

  /**
   * Builds the dead-letter admin page.
   *
   * @return array<string, mixed>
   *   Render array.
   */
  public function listing(): array {
    $total = $this->deadLetterStorage->count();
    $pager = $this->pagerManager->createPager($total, self::PAGE_LIMIT);
    $entries = $this->deadLetterStorage->getAll(
      self::PAGE_LIMIT,
      $pager->getCurrentPage() * self::PAGE_LIMIT,
    );

    $mediaIds = array_map(static fn(array $entry): int => $entry['media_id'], $entries);
    $mediaStorage = $this->mediaEntityTypeManager->getStorage('media');
    $mediaEntities = $mediaIds !== [] ? $mediaStorage->loadMultiple(array_values(array_unique($mediaIds))) : [];

    $rows = [];
    foreach ($entries as $entry) {
      $mediaLabel = $this->buildMediaLabel($entry, $mediaEntities);
      $rows[] = [
        'media' => ['data' => ['#plain_text' => $mediaLabel]],
        'field' => ['data' => ['#plain_text' => $entry['field_name'] !== '' ? $entry['field_name'] : 'Default']],
        'error_code' => ['data' => ['#plain_text' => $entry['last_error_code'] ?? '-']],
        'retry_count' => ['data' => ['#plain_text' => (string) $entry['retry_count']]],
        'failed_at' => ['data' => ['#plain_text' => $this->dateFormatter->format($entry['failed_at'], 'short')]],
        'error_message' => ['data' => ['#plain_text' => Unicode::truncate($entry['error_message'], 200, TRUE, TRUE)]],
      ];
    }

    return [
      'summary' => [
        '#type' => 'item',
        '#markup' => $this->formatPlural($total, '1 dead-letter entry', '@count dead-letter entries'),
      ],
      'table' => [
        '#type' => 'table',
        '#header' => [
          $this->t('Media'),
          $this->t('Field'),
          $this->t('Error code'),
          $this->t('Retries'),
          $this->t('Failed'),
          $this->t('Error message'),
        ],
        '#rows' => $rows,
        '#empty' => $this->t('No dead-letter entries found.'),
      ],
      'pager' => [
        '#type' => 'pager',
      ],
      '#cache' => [
        'max-age' => 0,
      ],
    ];
  }

  /**
   * Builds a readable media label for a dead-letter entry.
   *
   * @param array{id: int, media_id: int, field_name: string, error_message: string, retry_count: int, failed_at: int, profile_id: string|null, last_error_code: string|null} $entry
   *   Dead-letter entry.
   * @param array<int|string, \Drupal\Core\Entity\EntityInterface> $mediaEntities
   *   Loaded media entities keyed by entity ID.
   *
   * @return string
   *   Human-readable media label.
   */
  private function buildMediaLabel(array $entry, array $mediaEntities): string {
    $mediaId = $entry['media_id'];
    $media = $mediaEntities[$mediaId] ?? NULL;

    if ($media !== NULL) {
      return $media->label() . ' (#' . $mediaId . ')';
    }

    return 'Media #' . $mediaId;
  }

}
