using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace NodePipeline.Engine.Tests.CodeGeneratorTests.Fixtures;

public static class RoslynTestHelpers
{
    /// <summary>
    ///     Создаёт Roslyn Compilation из исходников мок-нод, находит и возвращает INamedTypeSymbol по полному имени типа.
    /// </summary>
    /// <param name="fullTypeName">
    ///     Полное имя типа, например,
    ///     "NodePipeline.Engine.Tests.CodeGeneratorTests.Fixtures.MockNodes.ThreePortNode2"
    /// </param>
    /// <param name="sourceFilesDirectory">Путь к папке с исходниками мок-нод (например, в тестовом проекте)</param>
    /// <returns>INamedTypeSymbol для указанного типа</returns>
    public static INamedTypeSymbol GetNamedTypeSymbolFromSource(string fullTypeName, string sourceFilesDirectory)
    {
        if (!Directory.Exists(sourceFilesDirectory))
            throw new DirectoryNotFoundException($"Source files directory not found: {sourceFilesDirectory}");

        var sourceFiles = Directory.GetFiles(sourceFilesDirectory, "*.cs", SearchOption.AllDirectories);

        var syntaxTrees = new List<SyntaxTree>();
        foreach (var file in sourceFiles)
        {
            var sourceText = File.ReadAllText(file);
            var syntaxTree = CSharpSyntaxTree.ParseText(sourceText, path: file);
            syntaxTrees.Add(syntaxTree);
        }

        var references = AppDomain.CurrentDomain.GetAssemblies()
            .Where(a => !a.IsDynamic && !string.IsNullOrEmpty(a.Location))
            .Select(a => MetadataReference.CreateFromFile(a.Location))
            .Cast<MetadataReference>()
            .ToList();

        var compilation = CSharpCompilation.Create("MockNodesCompilation",
            syntaxTrees,
            references,
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

        var typeSymbol = compilation.GetTypeByMetadataName(fullTypeName);
        if (typeSymbol == null)
            throw new InvalidOperationException($"Type symbol '{fullTypeName}' not found in compilation.");

        return typeSymbol;
    }
}