<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media\Service;

/**
 * Parses FFmpeg progress output into percentage values.
 *
 * @internal
 */
final class ProgressParser implements ProgressParserInterface {

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function parseProgress(string $buffer, ?float $totalDuration): ?int {
    if ($totalDuration === NULL || $totalDuration <= 0) {
      return NULL;
    }

    // Parse time from FFmpeg progress output.
    // Format 1: out_time_ms=123456789 (microseconds).
    if (preg_match('/out_time_ms=(\d+)/', $buffer, $matches)) {
      $currentTimeMs = (int) $matches[1];
      $currentTimeSeconds = $currentTimeMs / 1_000_000;
      $percentage = (int) min(99, ($currentTimeSeconds / $totalDuration) * 100);
      return max(0, $percentage);
    }

    // Format 2: out_time=HH:MM:SS.microseconds
    // (e.g., out_time=00:01:23.456789).
    if (preg_match('/out_time=(\d+):(\d+):(\d+)\.(\d+)/', $buffer, $matches)) {
      $hours = (int) $matches[1];
      $minutes = (int) $matches[2];
      $seconds = (int) $matches[3];
      $microseconds = (int) str_pad($matches[4], 6, '0');
      $currentTimeSeconds = ($hours * 3600) + ($minutes * 60) + $seconds + ($microseconds / 1_000_000);
      $percentage = (int) min(99, ($currentTimeSeconds / $totalDuration) * 100);
      return max(0, $percentage);
    }

    // Format 3: time=HH:MM:SS.XX (standard FFmpeg progress,
    // e.g., time=00:01:23.45).
    if (preg_match('/time=(\d+):(\d+):(\d+)\.(\d+)/', $buffer, $matches)) {
      $hours = (int) $matches[1];
      $minutes = (int) $matches[2];
      $seconds = (int) $matches[3];
      $fraction = (float) ('0.' . $matches[4]);
      $currentTimeSeconds = ($hours * 3600) + ($minutes * 60) + $seconds + $fraction;
      $percentage = (int) min(99, ($currentTimeSeconds / $totalDuration) * 100);
      return max(0, $percentage);
    }

    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function parseElapsedTime(string $buffer): ?float {
    // Format 1: out_time_ms=123456789 (microseconds).
    if (preg_match('/out_time_ms=(\d+)/', $buffer, $matches)) {
      return (int) $matches[1] / 1_000_000;
    }

    // Format 2: out_time=HH:MM:SS.microseconds.
    if (preg_match('/out_time=(\d+):(\d+):(\d+)\.(\d+)/', $buffer, $matches)) {
      $microseconds = (int) str_pad($matches[4], 6, '0');
      return ((int) $matches[1] * 3600)
        + ((int) $matches[2] * 60)
        + (int) $matches[3]
        + ($microseconds / 1_000_000);
    }

    // Format 3: time=HH:MM:SS.XX.
    if (preg_match('/time=(\d+):(\d+):(\d+)\.(\d+)/', $buffer, $matches)) {
      return ((int) $matches[1] * 3600)
        + ((int) $matches[2] * 60)
        + (int) $matches[3]
        + (float) ('0.' . $matches[4]);
    }

    return NULL;
  }

}
