using AmiReel.Services;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace AmiReel.Tests.Services;

[TestClass]
public class UserFacingErrorsTests
{
    [TestMethod]
    public void Summarize_WithBlankMessage_ReturnsGenericMessage()
    {
        // Arrange
        Exception exception = new("   ");

        // Act
        string result = UserFacingErrors.Summarize(exception);

        // Assert
        Assert.AreEqual("An unexpected error occurred.", result);
    }

    [TestMethod]
    public void Summarize_WithNonProcessExitMessage_ReturnsMessageUnchanged()
    {
        // Arrange
        Exception exception = new("The output directory could not be created.");

        // Act
        string result = UserFacingErrors.Summarize(exception);

        // Assert
        Assert.AreEqual("The output directory could not be created.", result);
    }

    [TestMethod]
    public void Summarize_WithProcessExitAndOnlyBoilerplateLines_ReturnsFirstLineOnly()
    {
        // Arrange
        Exception exception = new(
            "Process exited with code 1.\n" +
            "ffmpeg version 6.0\n" +
            "built with gcc\n" +
            "Input #0, avi, from 'clip.avi':\n" +
            "Duration: 00:01:00.00\n");

        // Act
        string result = UserFacingErrors.Summarize(exception);

        // Assert
        Assert.AreEqual("Process exited with code 1.", result);
    }

    [TestMethod]
    public void Summarize_WithProcessExitAndRealErrorLines_IncludesTheRealErrorLines()
    {
        // Arrange
        Exception exception = new(
            "Process exited with code 1.\n" +
            "ffmpeg version 6.0\n" +
            "[h264_nvenc @ 0x1] Cannot load libnvidia-encode.so.1\n" +
            "Error initializing output stream 0:0 -- Error while opening encoder\n");

        // Act
        string result = UserFacingErrors.Summarize(exception);

        // Assert
        StringAssert.Contains(result, "Process exited with code 1.");
        StringAssert.Contains(result, "Cannot load libnvidia-encode.so.1");
        StringAssert.Contains(result, "Error while opening encoder");
    }

    [TestMethod]
    public void Summarize_WithMoreThanThreeErrorLines_KeepsOnlyTheLastThree()
    {
        // Arrange
        Exception exception = new(
            "Process exited with code 1.\n" +
            "error line 1\n" +
            "error line 2\n" +
            "error line 3\n" +
            "error line 4\n");

        // Act
        string result = UserFacingErrors.Summarize(exception);
        string[] lines = result.Split(Environment.NewLine);

        // Assert
        Assert.AreEqual(4, lines.Length);
        CollectionAssert.DoesNotContain(lines, "error line 1");
        CollectionAssert.Contains(lines, "error line 4");
    }

    [TestMethod]
    [DataRow("ffmpeg version 6.0")]
    [DataRow("built with gcc 12")]
    [DataRow("Input #0, avi, from 'clip.avi':")]
    [DataRow("Duration: 00:01:00.00, start: 0.000000")]
    [DataRow("Stream #0:0: Video: mjpeg")]
    public void IsNoise_WithFfmpegBoilerplate_ReturnsTrue(string line)
    {
        // Act
        bool result = UserFacingErrors.IsNoise(line);

        // Assert
        Assert.IsTrue(result);
    }

    [TestMethod]
    [DataRow("Error while opening encoder for output stream")]
    [DataRow("Cannot load libnvidia-encode.so.1")]
    [DataRow("No such file or directory")]
    public void IsNoise_WithRealErrorText_ReturnsFalse(string line)
    {
        // Act
        bool result = UserFacingErrors.IsNoise(line);

        // Assert
        Assert.IsFalse(result);
    }
}
