<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media_ui\Service;

use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\ffmpeg_media\Utility\QueueItemKey;

/**
 * Builds dashboard render arrays from prepared data.
 *
 * @internal
 */
final class DashboardBuilderService implements DashboardBuilderServiceInterface {

  use StringTranslationTrait;

  /**
   * Constructs a DashboardBuilderService object.
   *
   * @param \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter
   *   Date formatter service.
   */
  public function __construct(
    protected readonly DateFormatterInterface $dateFormatter,
  ) {}

  /**
   * {@inheritdoc}
   *
   * @phpstan-param array<string, mixed> $conversionStats
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildStatsCards(array $conversionStats): array {
    $cards = [
      '#type' => 'container',
      '#attributes' => ['class' => ['ffmpeg-stats-cards-grid']],
    ];

    $cardData = [
      'total' => [
        'value' => $conversionStats['total'] ?? 0,
        'label' => $this->t('Total Conversions'),
        'modifier' => 'total',
        'stat' => 'total',
      ],
      'completed' => [
        'value' => $conversionStats['completed'] ?? 0,
        'label' => $this->t('Completed'),
        'modifier' => 'completed',
        'stat' => 'completed',
      ],
      'failed' => [
        'value' => $conversionStats['failed'] ?? 0,
        'label' => $this->t('Failed'),
        'modifier' => 'failed',
        'stat' => 'failed',
      ],
      'pending' => [
        'value' => $conversionStats['pending'] ?? 0,
        'label' => $this->t('Pending'),
        'modifier' => 'pending',
        'stat' => 'pending',
      ],
      'converting' => [
        'value' => $conversionStats['converting'] ?? 0,
        'label' => $this->t('In Progress'),
        'modifier' => 'converting',
        'stat' => 'converting',
      ],
      'success_rate' => [
        'value' => ($conversionStats['success_rate'] ?? 0) . '%',
        'label' => $this->t('Success Rate'),
        'modifier' => 'success-rate',
        'stat' => 'success_rate',
      ],
    ];

    foreach ($cardData as $key => $data) {
      $cards[$key] = [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['ffmpeg-stats-card', 'ffmpeg-stats-card--' . $data['modifier']],
          'aria-label' => $this->t('@label: @value', [
            '@label' => $data['label'],
            '@value' => $data['value'],
          ]),
        ],
        'value' => [
          '#type' => 'html_tag',
          '#tag' => 'div',
          '#value' => $data['value'],
          '#attributes' => [
            'class' => ['ffmpeg-stats-card__value'],
            'data-stat' => $data['stat'],
          ],
        ],
        'label' => [
          '#type' => 'html_tag',
          '#tag' => 'div',
          '#value' => $data['label'],
          '#attributes' => ['class' => ['ffmpeg-stats-card__label']],
        ],
      ];
    }

    return $cards;
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-param array<string, mixed> $dailyStats
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildStats24h(array $dailyStats): array {
    return [
      '#type' => 'container',
      '#attributes' => ['class' => ['ffmpeg-stats-24h-grid']],
      'completed' => $this->buildStatItem(
        (string) ($dailyStats['completed'] ?? 0),
        $this->t('Completed'),
        '24h_completed',
      ),
      'failed' => $this->buildStatItem(
        (string) ($dailyStats['failed'] ?? 0),
        $this->t('Failed'),
        '24h_failed',
      ),
      'success_rate' => $this->buildStatItem(
        ($dailyStats['success_rate'] ?? 0) . '%',
        $this->t('Success Rate'),
        '24h_success_rate',
      ),
      'avg_time' => $this->buildStatItem(
        !empty($dailyStats['average_time']) ? round($dailyStats['average_time']) . 's' : (string) $this->t('N/A'),
        $this->t('Avg. Time'),
        '24h_avg_time',
      ),
    ];
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-param array<string, mixed> $ffmpegStatus
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildSystemStatus(array $ffmpegStatus): array {
    return [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'ffmpeg-media-dashboard__section',
          'ffmpeg-media-dashboard__system-status',
        ],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-param array<int, array<string, mixed>> $activeConversions
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildActiveConversions(array $activeConversions): array {
    return [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'ffmpeg-media-dashboard__section',
          'ffmpeg-media-dashboard__active',
        ],
        'data-active-conversions' => '',
      ],
      'count' => count($activeConversions),
      'items' => $activeConversions,
      'has_items' => !empty($activeConversions),
    ];
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-param array<int, array<string, mixed>> $recentConversions
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildRecentConversions(array $recentConversions): array {
    return [
      'items' => $recentConversions,
      'has_items' => !empty($recentConversions),
    ];
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-param array<int, array<string, mixed>> $recentFailures
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildRecentFailures(array $recentFailures): array {
    return [
      'items' => $recentFailures,
      'count' => count($recentFailures),
      'has_items' => !empty($recentFailures),
    ];
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-param array<int, array<string, mixed>> $items
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildMediaTable(array $items): array {
    $rows = [];

    foreach ($items as $item) {
      $statusBadge = $this->buildStatusBadge($item['status'] ?? 'none');

      $updatedDisplay = '';
      if (!empty($item['updated'])) {
        $updatedDisplay = $this->dateFormatter->format((int) $item['updated'], 'short');
      }

      $outputIndicators = $item['output_badges'] ?? ['#markup' => ''];

      $operationLinks = is_array($item['operations'] ?? NULL) ? $item['operations'] : [];
      $operations = $operationLinks !== []
        ? [
          '#type' => 'operations',
          '#links' => $operationLinks,
        ]
        : ['#markup' => ''];

      $fieldName = (string) ($item['field_name'] ?? '');
      $itemId = (string) ($item['item_id'] ?? QueueItemKey::fromParts((int) ($item['media_id'] ?? 0), $fieldName));
      $routeOptions = $fieldName !== '' ? ['query' => ['field_name' => $fieldName]] : [];
      $mediaLink = [
        '#type' => 'link',
        '#title' => $item['label'] ?? '',
        '#url' => Url::fromRoute('ffmpeg_media_ui.status', ['media' => $item['media_id']], $routeOptions),
      ];
      $fieldContextLabel = '';
      if (!empty($item['field_label'])) {
        $fieldContextLabel = $fieldName !== ''
          ? (string) $this->t('@label (@field)', [
            '@label' => $item['field_label'],
            '@field' => $fieldName,
          ])
          : (string) $item['field_label'];
      }

      $mediaCell = $fieldContextLabel !== ''
        ? [
          '#type' => 'container',
          '#attributes' => ['class' => ['ffmpeg-media-table__media']],
          'link' => $mediaLink,
          'context' => [
            '#type' => 'html_tag',
            '#tag' => 'div',
            '#value' => $fieldContextLabel,
            '#attributes' => ['class' => ['ffmpeg-media-table__context']],
          ],
        ]
        : $mediaLink;

      $rows[] = [
        'data' => [
          [
            'data' => $mediaCell,
          ],
          ['data' => ['#plain_text' => $item['bundle_label'] ?? '']],
          ['data' => $statusBadge],
          ['data' => $outputIndicators],
          ['data' => $updatedDisplay],
          ['data' => $operations],
        ],
        'data-media-id' => $item['media_id'],
        'data-field-name' => $fieldName,
        'data-item-id' => $itemId,
        'class' => ['ffmpeg-media-item', 'ffmpeg-status--' . ($item['status'] ?? 'none')],
      ];
    }

    return [
      '#type' => 'table',
      '#header' => [
        $this->t('Media'),
        $this->t('Bundle'),
        $this->t('Status'),
        $this->t('Outputs'),
        $this->t('Updated'),
        $this->t('Operations'),
      ],
      '#rows' => $rows,
      '#empty' => $this->t('No video media found.'),
      '#attributes' => ['class' => ['ffmpeg-media-table']],
    ];
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-param array<string, mixed> $queueStatus
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildEnhancedQueueStatus(array $queueStatus): array {
    $authoritativeQueuedCount = (int) ($queueStatus['queued_media'] ?? $queueStatus['total_count'] ?? 0);

    return [
      '#type' => 'container',
      '#attributes' => ['class' => ['ffmpeg-queue-status-grid']],
      'normal' => [
        '#type' => 'container',
        '#attributes' => ['class' => ['queue-item']],
        'value' => [
          '#type' => 'html_tag',
          '#tag' => 'span',
          '#value' => $queueStatus['normal_count'],
          '#attributes' => [
            'class' => ['queue-item__value'],
            'data-stat' => 'queue_normal',
          ],
        ],
        'label' => [
          '#type' => 'html_tag',
          '#tag' => 'span',
          '#value' => $this->t('Normal Queue'),
          '#attributes' => ['class' => ['queue-item__label']],
        ],
      ],
      'large' => [
        '#type' => 'container',
        '#attributes' => ['class' => ['queue-item']],
        'value' => [
          '#type' => 'html_tag',
          '#tag' => 'span',
          '#value' => $queueStatus['large_count'],
          '#attributes' => [
            'class' => ['queue-item__value'],
            'data-stat' => 'queue_large',
          ],
        ],
        'label' => [
          '#type' => 'html_tag',
          '#tag' => 'span',
          '#value' => $this->t('Large Files Queue'),
          '#attributes' => ['class' => ['queue-item__label']],
        ],
      ],
      'total' => [
        '#type' => 'container',
        '#attributes' => ['class' => ['queue-item', 'queue-item--total']],
        'value' => [
          '#type' => 'html_tag',
          '#tag' => 'span',
          '#value' => $authoritativeQueuedCount,
          '#attributes' => [
            'class' => ['queue-item__value'],
            'data-stat' => 'queue_total',
          ],
        ],
        'label' => [
          '#type' => 'html_tag',
          '#tag' => 'span',
          '#value' => $this->t('Queued Items'),
          '#attributes' => ['class' => ['queue-item__label']],
        ],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildStatusFilter(string $currentFilter): array {
    $filters = [
      '' => $this->t('All'),
      'none' => $this->t('Not Started'),
      'pending' => $this->t('Pending'),
      'processing' => $this->t('Processing'),
      'completed' => $this->t('Completed'),
      'failed' => $this->t('Failed'),
    ];

    $links = [];
    foreach ($filters as $value => $label) {
      $isActive = $currentFilter === $value;
      $query = $value !== '' ? ['status' => $value] : [];

      $attributes = [
        'class' => [
          'ffmpeg-filter-link',
          $isActive ? 'ffmpeg-filter-link--active' : '',
        ],
      ];
      if ($isActive) {
        $attributes['aria-current'] = 'true';
      }

      $links['filter_' . ($value ?: 'all')] = [
        '#type' => 'link',
        '#title' => $label,
        '#url' => Url::fromRoute('ffmpeg_media_ui.dashboard', [], ['query' => $query]),
        '#attributes' => $attributes,
      ];
    }

    return [
      '#type' => 'container',
      '#attributes' => [
        'class' => ['ffmpeg-status-filter'],
        'role' => 'navigation',
        'aria-label' => $this->t('Filter by status'),
      ],
    ] + $links;
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildSetupAlert(bool $hasMappings, string $configUrl): array {
    if ($hasMappings) {
      return [];
    }

    return [
      '#type' => 'container',
      '#attributes' => ['class' => ['messages', 'messages--warning']],
      'message' => [
        '#type' => 'html_tag',
        '#tag' => 'p',
        '#value' => $this->t('FFmpeg Media has no auto-convert formatter configured. Enable auto-convert in a video field formatter on any <a href="@url">media view display</a> to start converting videos.', [
          '@url' => $configUrl,
        ]),
      ],
    ];
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildStatusBadge(string $status): array {
    // 'converting' is internal status, map to 'processing' for display.
    $displayStatus = $status === 'converting' ? 'processing' : $status;

    $labels = [
      'pending' => $this->t('Pending'),
      'processing' => $this->t('Processing'),
      'completed' => $this->t('Completed'),
      'failed' => $this->t('Failed'),
      'none' => $this->t('Not Started'),
    ];

    return [
      '#type' => 'html_tag',
      '#tag' => 'span',
      '#value' => $labels[$displayStatus] ?? $displayStatus,
      '#attributes' => [
        'class' => ['ffmpeg-status-badge', 'ffmpeg-status-badge--' . $displayStatus],
      ],
    ];
  }

  /**
   * Builds a single stat item render array.
   *
   * @param string $value
   *   Display value.
   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|\Stringable|string $label
   *   Label text.
   * @param string $dataStat
   *   Data-stat attribute value.
   *
   * @phpstan-return array<string, mixed>
   *   Render array.
   */
  protected function buildStatItem(string $value, \Stringable|string $label, string $dataStat): array {
    return [
      '#type' => 'container',
      '#attributes' => ['class' => ['ffmpeg-stat-item']],
      'value' => [
        '#type' => 'html_tag',
        '#tag' => 'span',
        '#value' => $value,
        '#attributes' => [
          'class' => ['ffmpeg-stat-item__value'],
          'data-stat' => $dataStat,
        ],
      ],
      'label' => [
        '#type' => 'html_tag',
        '#tag' => 'span',
        '#value' => $label,
        '#attributes' => ['class' => ['ffmpeg-stat-item__label']],
      ],
    ];
  }

}
