namespace ErsatzTV.Core.FFmpeg;

/// <summary>
/// Heavy transcode features detected from a cold-start's FFmpeg arguments, so each HLS
/// cold-start latency sample is self-describing (#350). Only cleanly-detectable signals are
/// surfaced: subtitle burn-in (the libass <c>subtitles=</c> text filter) and the hardware
/// acceleration family. Watermark, HDR-&gt;SDR, and <em>image</em>-based subtitle burn-in are
/// intentionally NOT flagged here: in the argument string they all reduce to <c>overlay=</c>,
/// indistinguishable from one another, so a boolean would mislead the very measurement it
/// serves. Inspect the full <c>ffmpeg hls arguments</c> debug log for those details.
/// Detection is a case-sensitive substring scan of the whole argument string (which includes
/// the input media path), so a media filename literally containing e.g. <c>subtitles=</c> or
/// <c>_amf</c> could false-positive; this is telemetry-only (no behavior impact) and low-probability.
/// </summary>
public readonly record struct ColdStartFeatures(bool SubtitleBurnIn, string HardwareAcceleration)
{
    // Encoder/filter suffix -> accel family. Matching any of these substrings means the
    // pipeline is that hardware family (the encoder codec, e.g. h264_vaapi, dominates
    // cold-start encoder init cost; VAAPI/QSV/CUDA filters carry the same suffix).
    private static readonly (string Token, string Family)[] HardwareFamilies =
    [
        ("_vaapi", "vaapi"),
        ("_nvenc", "nvenc"),
        ("_qsv", "qsv"),
        ("_videotoolbox", "videotoolbox"),
        ("_amf", "amf"),
        ("_rkmpp", "rkmpp")
    ];

    public static ColdStartFeatures FromFFmpegArguments(string arguments)
    {
        if (string.IsNullOrWhiteSpace(arguments))
        {
            return new ColdStartFeatures(false, "unknown");
        }

        bool subtitleBurnIn = arguments.Contains("subtitles=", StringComparison.Ordinal);
        return new ColdStartFeatures(subtitleBurnIn, DetectHardwareAcceleration(arguments));
    }

    private static string DetectHardwareAcceleration(string arguments)
    {
        foreach ((string token, string family) in HardwareFamilies)
        {
            if (arguments.Contains(token, StringComparison.Ordinal))
            {
                return family;
            }
        }

        // No hardware encoder/filter present: fall back to the decode accel (a hardware
        // decode + software encode still pays an init cost worth attributing).
        const string HwAccelFlag = "-hwaccel ";
        int index = arguments.IndexOf(HwAccelFlag, StringComparison.Ordinal);
        if (index >= 0)
        {
            string rest = arguments[(index + HwAccelFlag.Length)..].TrimStart();
            int end = rest.IndexOf(' ');
            string value = end >= 0 ? rest[..end] : rest;
            if (value.Length > 0)
            {
                return value;
            }
        }

        return "software";
    }
}
