using System.Text.RegularExpressions;

namespace ytLive.Services.Encoder;

/// <summary>A decoded ffmpeg <c>-stats</c> progress line (pure data).</summary>
public readonly record struct FfmpegProgress(
    long Frame,
    double Fps,
    double BitrateKbps,
    TimeSpan Duration,
    long SizeBytes);

/// <summary>
/// Pure parser for ffmpeg's periodic <c>frame= fps= size= time= bitrate=</c> stderr
/// lines (the <c>-stats</c>/<c>-stats_period</c> output). Unit-tested in isolation
/// so the encoder loop stays a thin wire.
/// </summary>
public static class FfmpegProgressParser
{
    // frame=  123 fps= 59.9 q=28.0 size=   1024KiB time=00:00:02.04 bitrate= 4000.1kbits/s speed=1.00x
    private static readonly Regex Line = new(
        @"frame=\s*(?<frame>\d+)\s+fps=\s*(?<fps>[\d.]+).*?"
        + @"size=\s*(?<size>\d+)KiB.*?"
        + @"time=(?<time>\d{2}):(?<min>\d{2}):(?<sec>[\d.]+).*?"
        + @"bitrate=\s*(?<bitrate>[\d.]+)kbits/s",
        RegexOptions.Compiled | RegexOptions.CultureInvariant);

    /// <summary>Returns null for non-progress lines (errors, warnings, banner).</summary>
    public static FfmpegProgress? TryParse(string line)
    {
        if (string.IsNullOrWhiteSpace(line)) return null;
        var m = Line.Match(line);
        if (!m.Success) return null;

        var frame = long.Parse(m.Groups["frame"].Value);
        var fps = double.Parse(m.Groups["fps"].Value, System.Globalization.CultureInfo.InvariantCulture);
        var size = long.Parse(m.Groups["size"].Value);
        var bitrate = double.Parse(m.Groups["bitrate"].Value, System.Globalization.CultureInfo.InvariantCulture);

        var hours = int.Parse(m.Groups["time"].Value);
        var minutes = int.Parse(m.Groups["min"].Value);
        var seconds = double.Parse(m.Groups["sec"].Value, System.Globalization.CultureInfo.InvariantCulture);
        var duration = TimeSpan.FromSeconds(hours * 3600 + minutes * 60 + seconds);

        return new FfmpegProgress(frame, fps, bitrate, duration, size * 1024);
    }
}
