<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media\Plugin\FFmpegCodec;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\ffmpeg_media\Attribute\FFmpegCodec;
use Drupal\ffmpeg_media\ValueObject\ConversionOptions;

/**
 * AV1 codec plugin using SVT-AV1.
 */
#[FFmpegCodec(
  id: 'av1',
  label: new TranslatableMarkup('AV1'),
  description: new TranslatableMarkup('Next-generation codec with excellent compression. Requires FFmpeg 8+.'),
  encoder: 'libsvtav1',
  supportedContainers: ['webm', 'mp4', 'mkv', 'hls', 'dash', 'whip', 'rtp'],
  hardwareAccelerated: FALSE,
  twoPassSupported: TRUE,
  weight: 20,
)]
final class AV1Codec extends FFmpegCodecBase {

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function buildArguments(ConversionOptions $options): array {
    $args = [
      '-c:v', 'libsvtav1',
      '-preset', (string) $options->preset,
    ];

    // Build SVT-AV1 params.
    $svtParams = ['tune=0'];

    // Add rate control settings.
    if ($options->rateControl !== NULL) {
      $args = array_merge($args, $options->rateControl->buildArguments('av1'));
    }
    else {
      // Default CRF mode.
      $args[] = '-crf';
      $args[] = (string) $options->crf;
    }

    // Add GOP/keyframe settings.
    if ($options->gopSettings !== NULL) {
      $args = array_merge($args, $options->gopSettings->buildArguments('av1'));
      // SVT-AV1 specific: use keyint param.
      if ($options->gopSettings->keyframeInterval > 0) {
        $svtParams[] = 'keyint=' . $options->gopSettings->keyframeInterval;
      }
    }

    // Add SVT-AV1 params.
    $args[] = '-svtav1-params';
    $args[] = implode(':', $svtParams);

    // Add common video arguments.
    $args = array_merge($args, $this->buildCommonArguments($options));

    // Audio arguments (Opus preference configured via getDefaultOptions).
    $args = array_merge($args, $this->buildAudioArguments($options));

    // Add extra arguments.
    foreach ($options->extraArgs as $arg) {
      $args[] = $arg;
    }

    return $args;
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function getDefaultOptions(): ConversionOptions {
    return new ConversionOptions(
      crf: 30,
      preset: 6,
      threads: 0,
      audioBitrate: '128k',
      audioCodec: 'libopus',
      pixelFormat: 'yuv420p',
    );
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function getHighQualityOptions(): ConversionOptions {
    return new ConversionOptions(
      crf: 23,
      preset: 4,
      threads: 0,
      audioBitrate: '192k',
      audioCodec: 'libopus',
      pixelFormat: 'yuv420p10le',
    );
  }

}
