using ImageConvertService.Biz.Models;

using SevenZip;

namespace ImageConvertService.Biz;

public class ArchiveFileAccessor
{
    static ArchiveFileAccessor()
    {
        SevenZipBase.SetLibraryPath(@"C:\Program Files\7-Zip\7z.dll");
    }

    public ArchiveEntry[] ReadArchive(byte[] input) => ReadArchive(new MemoryStream(input));

    public ArchiveEntry[] ReadArchive(Stream stream)
    {
        using var sze = new SevenZipExtractor(stream);

        var ret = new List<ArchiveEntry>(sze.ArchiveFileData.Count(p => p.IsDirectory == false));

        foreach (var archiveFileInfo in sze.ArchiveFileData)
        {
            if (archiveFileInfo.IsDirectory) continue;
            var item = new ArchiveEntry
            {
                PathAndName = archiveFileInfo.FileName,
                LastWrite = archiveFileInfo.LastWriteTime,
                LastAccess = archiveFileInfo.LastAccessTime,
                CreateTime = archiveFileInfo.CreationTime,
            };

            var ms = new MemoryStream();
            sze.ExtractFile(archiveFileInfo.Index, ms);
            item.Content = ms.ToArray();

            ret.Add(item);
        }

        return ret.ToArray();
    }

    public byte[] MakeArchiveFastZip(IReadOnlyList<ArchiveEntry> input)
    {
        var compressor = new SevenZipCompressor
        {
            CompressionLevel = CompressionLevel.Fast,
            ArchiveFormat = OutArchiveFormat.Zip,
            CustomParameters =
            {
                { "mt", "on" },
            }
        };

        var msZip = new MemoryStream();

        compressor.CompressStreamDictionaryWithFileTime(
            input.ToDictionary(
                p => p.PathAndName,
                p => new CompressStreamEntry(new MemoryStream(p.Content), p.CreateTime, p.LastWrite, p.LastAccess)
            )
            , msZip
        );

        return msZip.ToArray();
    }

    public byte[] MakeArchiveFast7Z(IReadOnlyList<ArchiveEntry> input)
    {
        var compressor = new SevenZipCompressor
        {
            CompressionLevel = CompressionLevel.Fast,
            ArchiveFormat = OutArchiveFormat.SevenZip,
            CustomParameters =
            {
                { "mt", "on" },
                { "s", "off" },
            }
        };

        var msZip = new MemoryStream();

        compressor.CompressStreamDictionaryWithFileTime(
            input.ToDictionary(
                p => p.PathAndName,
                p => new CompressStreamEntry(new MemoryStream(p.Content), p.CreateTime, p.LastWrite, p.LastAccess)
            )
            , msZip
        );

        return msZip.ToArray();
    }
}