<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media\Service;

use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\ffmpeg_media\ValueObject\ErrorCategory;

/**
 * Categorizes FFmpeg conversion errors with actionable suggestions.
 *
 * @internal
 */
final class ErrorCategorizationService implements ErrorCategorizationServiceInterface {

  use StringTranslationTrait;

  /**
   * Error pattern definitions, ordered from most to least specific.
   *
   * @var array<string, array{patterns: array<int, string>, severity: string}>
   */
  private const array CATEGORIES = [
    'hardware' => [
      'patterns' => [
        'NVENC',
        'VAAPI',
        'GPU',
        'initialization failed',
        'hwaccel',
        'h264_nvenc',
        'hevc_nvenc',
        'h264_vaapi',
      ],
      'severity' => 'warning',
    ],
    'disk_space' => [
      'patterns' => [
        'No space',
        'disk full',
        'ENOSPC',
        'no space left',
      ],
      'severity' => 'error',
    ],
    'permission' => [
      'patterns' => [
        'Permission denied',
        'EACCES',
        'not writable',
        'Operation not permitted',
      ],
      'severity' => 'error',
    ],
    'memory' => [
      'patterns' => [
        'Cannot allocate',
        'out of memory',
        'OOM',
        'memory allocation',
        'Allowed memory size',
      ],
      'severity' => 'error',
    ],
    'source' => [
      'patterns' => [
        'Source file not found',
        'Invalid data',
        'corrupt',
        'No such file',
        'does not exist',
        'Invalid source',
      ],
      'severity' => 'error',
    ],
    'timeout' => [
      'patterns' => [
        'timed out',
        'timeout',
        'exceeded',
        'Conversion timed out',
      ],
      'severity' => 'warning',
    ],
    'codec' => [
      'patterns' => [
        'Unknown encoder',
        'Encoder not found',
        'encoder',
        'codec',
        'libx264',
        'libx265',
        'libvpx',
        'libsvtav1',
      ],
      'severity' => 'error',
    ],
  ];

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function categorize(string $errorMessage): ErrorCategory {
    $lowerMessage = mb_strtolower($errorMessage);

    foreach (self::CATEGORIES as $categoryId => $config) {
      foreach ($config['patterns'] as $pattern) {
        if (str_contains($lowerMessage, mb_strtolower($pattern))) {
          [$label, $suggestion] = $this->getLabelAndSuggestion($categoryId);
          return new ErrorCategory(
            category: $categoryId,
            label: $label,
            suggestion: $suggestion,
            severity: $config['severity'],
          );
        }
      }
    }

    return new ErrorCategory(
      category: 'unknown',
      label: $this->t('Conversion Error'),
      suggestion: $this->t('Check the system log for more details.'),
      severity: 'error',
    );
  }

  /**
   * Returns translated label and suggestion for a category.
   *
   * @phpstan-return array{0: \Drupal\Core\StringTranslation\TranslatableMarkup, 1: \Drupal\Core\StringTranslation\TranslatableMarkup}
   */
  private function getLabelAndSuggestion(string $categoryId): array {
    return match ($categoryId) {
      'hardware' => [
        $this->t('Hardware Acceleration'),
        $this->t('Check GPU drivers or set hardware acceleration to "none" in settings.'),
      ],
      'disk_space' => [
        $this->t('Disk Space'),
        $this->t('Free up disk space in the output directory.'),
      ],
      'permission' => [
        $this->t('Permission Denied'),
        $this->t('Check file permissions on the output directory.'),
      ],
      'memory' => [
        $this->t('Memory'),
        $this->t('Reduce concurrent conversions or increase server memory.'),
      ],
      'source' => [
        $this->t('Source File'),
        $this->t('Re-upload the source video file.'),
      ],
      'timeout' => [
        $this->t('Timeout'),
        $this->t('Increase the FFmpeg timeout in settings or process shorter videos.'),
      ],
      'codec' => [
        $this->t('Codec Error'),
        $this->t('Check FFmpeg encoder support or disable hardware acceleration.'),
      ],
      default => [
        $this->t('Conversion Error'),
        $this->t('Check the system log for more details.'),
      ],
    };
  }

}
