using System;
using System.Collections.Generic;
using System.Xml;
using Microsoft.CodeAnalysis.CSharp;
using SharpGen.Generator;
using SharpGen.Model;
using SharpGen.Transform;
using Xunit;
using Xunit.Abstractions;

namespace SharpGen.UnitTests;

public class RoslynGeneratorTests : TestBase
{
    public RoslynGeneratorTests(ITestOutputHelper outputHelper) : base(outputHelper)
    {
    }

    [Fact]
    public void IncludeXmlDocIsNotMangled()
    {
        CsAssembly assembly = new();
        CsNamespace @namespace = new("Test");
        @namespace.Add(
            new CsStruct(null, "PAIR")
            {
                CppElementName = "PAIR"
            }
        );
        assembly.Add(@namespace);

        XmlDocument docs = new();
        docs.LoadXml(@"<comments><comment id=""PAIR"">Test</comment></comments>");

        AddIocServices(CreateExternalDocCommentsReader(docs));

        Assert.Collection(
            GenerateLines(assembly),
            x => Assert.Equal(@"// <auto-generated/>", x),
            x => Assert.Equal(@"namespace Test", x),
            x => Assert.Equal(@"{", x),
            x => Assert.Equal(@"/// <include file=""doc.xml"" path=""/comments/comment[@id='PAIR']/*"" />", x),
            x => Assert.Equal(@"/// <unmanaged>PAIR</unmanaged>", x),
            x => Assert.Equal(@"/// <unmanaged-short>PAIR</unmanaged-short>", x),
            x => Assert.Equal(@"[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]", x),
            x => Assert.Equal(@"public partial struct PAIR", x),
            x => Assert.Equal(@"{", x),
            x => Assert.Equal(@"}", x),
            x => Assert.Equal(@"}", x)
        );
    }

    private static Action<IocServiceContainer> CreateExternalDocCommentsReader(XmlDocument docs)
    {
        return container =>
            container.AddService(new ExternalDocCommentsReader(new Dictionary<string, XmlDocument> { ["doc.xml"] = docs }));
    }

    private Action<IocServiceContainer> CreateDefaultGenerators()
    {
        return container => container.AddService<IGeneratorRegistry>(new DefaultGenerators(Ioc));
    }

    private string[] GenerateLines(CsAssembly assembly)
    {
        AddIocServices(CreateDefaultGenerators());

        var root = new RoslynGenerator().Run(assembly, Ioc).GetCompilationUnitRoot();
        return root.ToFullString()
                   .Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
    }
}