<?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;

/**
 * VP9 codec plugin.
 */
#[FFmpegCodec(
  id: 'vp9',
  label: new TranslatableMarkup('VP9'),
  description: new TranslatableMarkup('High-quality open codec for WebM containers.'),
  encoder: 'libvpx-vp9',
  supportedContainers: ['webm', 'mkv', 'flv', 'dash', 'whip', 'rtp'],
  hardwareAccelerated: FALSE,
  twoPassSupported: TRUE,
  weight: 10,
)]
final class VP9Codec extends FFmpegCodecBase {

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function buildArguments(ConversionOptions $options): array {
    $args = [
      '-c:v', 'libvpx-vp9',
      '-cpu-used', (string) $this->getCpuUsed($options->preset),
      '-row-mt', '1',
    ];

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

    // Add GOP/keyframe settings.
    if ($options->gopSettings !== NULL) {
      $args = array_merge($args, $options->gopSettings->buildArguments('vp9'));
    }

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

    // Audio for WebM - force WebM-compatible audio codec.
    $webmAudioCodec = $options->audioCodec === 'libopus' ? 'libopus' : 'libvorbis';
    $webmOptions = $options->withAudioCodec($webmAudioCodec);
    $args = array_merge($args, $this->buildAudioArguments($webmOptions));

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

    return $args;
  }

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

  /**
   * Converts preset to cpu-used value.
   *
   * @param int $preset
   *   Numeric preset (0-9).
   *
   * @return int
   *   cpu-used value (0-8).
   */
  protected function getCpuUsed(int $preset): int {
    // VP9 cpu-used: 0 = slowest/best, 8 = fastest
    // Map 0-9 preset to 0-8 cpu-used.
    return min(8, (int) ($preset * 8 / 9));
  }

}
