using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using ILRepacking;
using Mono.Cecil;

public class BuildTasksPatcher
{
    public static void PatchBuildTasksInPackage(string packagePath)
    {
        using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
            ZipArchiveMode.Update))
        {

            foreach (var entry in archive.Entries.ToList())
            {
                if (entry.Name == "Avalonia.Build.Tasks.dll")
                {
                    var temp = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".dll");
                    var output = temp + ".output";
                    var patched = new MemoryStream();
                    try
                    {
                        entry.ExtractToFile(temp, true);
                        var repack = new ILRepacking.ILRepack(new RepackOptions()
                        {
                            Internalize = true,
                            InputAssemblies = new[]
                            {
                                temp, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0]
                                    .FullyQualifiedName,
                                typeof(Mono.Cecil.Rocks.MethodBodyRocks).Assembly.GetModules()[0].FullyQualifiedName,
                                typeof(Mono.Cecil.Pdb.PdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName,
                                typeof(Mono.Cecil.Mdb.MdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName
                                
                            },
                            SearchDirectories = new string[0],
                            OutputFile = output
                        });
                        repack.Repack();


                        // 'hurr-durr assembly with the same name is already loaded' prevention
                        using (var asm = AssemblyDefinition.ReadAssembly(output,
                            new ReaderParameters { ReadWrite = true, InMemory = true, }))
                        {
                            asm.Name = new AssemblyNameDefinition(
                                "Avalonia.Build.Tasks."
                                + Guid.NewGuid().ToString().Replace("-", ""),
                                new Version(0, 0, 0));
                            asm.Write(patched);
                            patched.Position = 0;
                        }
                    }
                    finally
                    {
                        try
                        {
                            if (File.Exists(temp))
                                File.Delete(temp);
                            if (File.Exists(output))
                                File.Delete(output);
                        }
                        catch
                        {
                            //ignore
                        }
                    }

                    var fn = entry.FullName;
                    entry.Delete();
                    var newEntry = archive.CreateEntry(fn, CompressionLevel.Optimal);
                    using (var s = newEntry.Open())
                        patched.CopyTo(s);
                }
            }
        }
    }
}