using System.Text;
using NodePipeline.Configuration.Abstractions.Models.Edit;
using NodePipeline.Configuration.Yaml.Exceptions;
using NodePipeline.Configuration.Yaml.Loader;

namespace NodePipeline.Configuration.Yaml.Tests;

public class YamlEditorConfigLoaderTests
{
    private const string ValidYaml = """
                                     name: test-pipeline
                                     description: test-description

                                     nodes:
                                       - id: node1
                                         type: FileImageSource
                                         title: Загрузчик
                                         description: Загрузка изображения
                                         parameters:
                                           FileName:
                                             value: "input.jpg"
                                             label: "Имя файла"
                                             description: "Файл для загрузки"
                                         inputs:
                                           Trigger:
                                             source: upstream.Done
                                             label: "Триггер"
                                             description: "Когда запускать"
                                         outputs:
                                           Output:
                                             label: "Выход"
                                             description: "Изображение"
                                     """;

    [Fact]
    public void LoadsPipelineMetadata()
    {
        const string name = "test-pipeline";
        const string description = "test-description";

        var config = LoadFromYaml(ValidYaml);

        Assert.Equal(name, config.Name);
        Assert.Equal(description, config.Description);
    }

    [Fact]
    public void LoadsSingleNode()
    {
        const string nodeId = "node1";
        const string nodeType = "FileImageSource";
        const string nodeTitle = "Загрузчик";
        const string nodeDescription = "Загрузка изображения";

        var config = LoadFromYaml(ValidYaml);

        Assert.Single(config.Nodes);
        var node = config.Nodes[0];
        Assert.Equal(nodeId, node.Id);
        Assert.Equal(nodeType, node.Type);
        Assert.Equal(nodeTitle, node.Title);
        Assert.Equal(nodeDescription, node.Description);
    }

    [Fact]
    public void LoadsNodeParameters()
    {
        const string paramName = "FileName";
        const string paramLabel = "Имя файла";
        const string paramDescription = "Файл для загрузки";
        const string paramValue = "input.jpg";

        var config = LoadFromYaml(ValidYaml);
        var param = config.Nodes[0].Parameters["FileName"];

        Assert.Equal(paramName, param.Name);
        Assert.Equal(paramLabel, param.Label);
        Assert.Equal(paramDescription, param.Description);
        Assert.Equal(paramValue, param.Value);
    }

    [Fact]
    public void LoadsNodeInputs()
    {
        const string inputName = "Trigger";
        const string inputLabel = "Триггер";
        const string inputSource = "upstream.Done";
        const string inputDescription = "Когда запускать";

        var config = LoadFromYaml(ValidYaml);
        var input = config.Nodes[0].Inputs["Trigger"];

        Assert.Equal(inputName, input.Name);
        Assert.Equal(inputLabel, input.Label);
        Assert.Equal(inputSource, input.Source);
        Assert.Equal(inputDescription, input.Description);
    }

    [Fact]
    public void LoadsNodeOutputs()
    {
        var outputName = "Output";
        var outputLabel = "Выход";
        var outputDescription = "Изображение";

        var config = LoadFromYaml(ValidYaml);
        var output = config.Nodes[0].Outputs["Output"];
        Assert.Equal(outputName, output.Name);
        Assert.Equal(outputLabel, output.Label);
        Assert.Equal(outputDescription, output.Description);
    }

    [Fact]
    public void HandlesEmptyYamlGracefully()
    {
        const string emptyYaml = "";
        var loader = new YamlEditorConfigLoader();
        var exceptionType = typeof(YamlFileIsEmptyException);

        Exception? exception = null;
        try
        {
            using var stream = new MemoryStream(Encoding.UTF8.GetBytes(emptyYaml));
            loader.Load(stream);
        }
        catch (Exception ex)
        {
            exception = ex;
        }

        Assert.NotNull(exception);
        Assert.Equal(exceptionType, exception.GetType());
    }

    private static EditorPipelineConfig LoadFromYaml(string yaml)
    {
        using var stream = new MemoryStream(Encoding.UTF8.GetBytes(yaml));
        var loader = new YamlEditorConfigLoader();
        return loader.Load(stream);
    }
}