using System.Text;
using Mono.Cecil;
using Serilog;

public class AssemblyRedirectionSourceGenerator
{
    public static void Generate(string assembliesFolderPath, string generatedFilePath)
    {
        Log.Debug("Generating assembly redirection file {0}", generatedFilePath);
        var assemblies = new SortedDictionary<string, AssemblyNameDefinition>();
        foreach (var fileName in Directory.EnumerateFiles(assembliesFolderPath))
        {
            try
            {
                using var moduleDef = ModuleDefinition.ReadModule(fileName);
                var assemblyDef = moduleDef.Assembly.Name!;
                if (assemblyDef.Name == "netstandard")
                {
                    // Skip netstandard, since it doesn't need redirection.
                    continue;
                }

                assemblies[assemblyDef.Name] = assemblyDef;
                Log.Debug("Adding {0} assembly to the redirection map. Targeted version {1}", assemblyDef.Name, assemblyDef.Version);
            }
            catch (BadImageFormatException)
            {
                Log.Debug("Skipping \"{0}\" couldn't open it as a managed assembly", fileName);
            }
        }

        var sourceContents = GenerateSourceContents(assemblies);

        File.WriteAllText(generatedFilePath, sourceContents);
        Log.Information("Assembly redirection source generated {0}", generatedFilePath);
    }

    static string GenerateSourceContents(SortedDictionary<string, AssemblyNameDefinition> assemblies)
    {
        var sb = new StringBuilder(assemblies.Count * 256);
        sb.AppendLine("""
    /*
     * Copyright The OpenTelemetry Authors
     * SPDX-License-Identifier: Apache-2.0
     */
    """);
        sb.AppendLine();
        sb.AppendLine($"// Auto-generated file, do not change it - generated by the {nameof(AssemblyRedirectionSourceGenerator)} type");
        sb.Append(@"
#include ""cor_profiler.h""

#ifdef _WIN32
namespace trace
{
void CorProfiler::InitNetFxAssemblyRedirectsMap()
{
    assembly_version_redirect_map_.insert({
");
        foreach (var kvp in assemblies)
        {
            var v = kvp.Value.Version!;
            sb.AppendLine($"        {{ L\"{kvp.Key}\", {{{v.Major}, {v.Minor}, {v.Build}, {v.Revision}}} }},");
        }

        sb.Append(@"    });
}
}
#endif
");

        return sb.ToString();
    }
}
