using SevenZip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace SevenRepacker
{
    internal class Program
    {
        private static int Main(string[] args)
        {
#if DEBUG
            SevenZipBase.SetLibraryPath(Environment.Is64BitProcess
                ? "x64/7z.dll"
                : "x86/7z.dll");
#else
            SevenZipBase.SetLibraryPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "7z.dll"));
#endif
            string outDir = null;
            string password = null;
            var banPrefix = new List<string>();
            var banSuffix = new List<string>();

            var inputFiles = new List<string>();

            foreach (var arg in args)
            {
                if (arg.StartsWith('/') && arg.Contains(':') && arg[^1] != ':')
                {
                    var kv = arg.Substring(1).Split(":", 2);
                    switch (kv[0].ToLower())
                    {
                        case "out-dir":
                            outDir = kv[1];
                            if (false == Directory.Exists(outDir))
                            {
                                Console.Error.WriteLine($"Arg ERROR. out dir not found: {outDir}");
                                return -1;
                            }
                            break;
                        case "ban-prefix":
                            banPrefix.Add(kv[1]);
                            break;
                        case "ban-suffix":
                            banSuffix.Add(kv[1]);
                            break;
                        case "pass":
                            password = kv[1];
                            break;
                    }
                    continue;
                }

                inputFiles.Add(arg);
            }

            foreach (var inputFilePath in inputFiles)
            {
                Console.WriteLine("Process start");

                if (!File.Exists(inputFilePath))
                {
                    Console.WriteLine($"ERR, Input file not found: {inputFilePath}");
                    continue;
                }

                var outputFilePath = Path.ChangeExtension(inputFilePath, ".zip");
                if (outDir != null)
                {
                    outputFilePath = Path.Combine(outDir, Path.GetFileName(outputFilePath));
                }

                if (File.Exists(outputFilePath))
                {
                    Console.WriteLine($"SKIP, Output file already exist: {outputFilePath}");
                    continue;
                }

                Console.WriteLine($"  In: {inputFilePath}");
                Console.WriteLine($" Out: {outputFilePath}");

                using var inputArchive = password == null
                    ? new SevenZipExtractor(inputFilePath)
                    : new SevenZipExtractor(inputFilePath, password);

                var inputItems = inputArchive.ArchiveFileData.OrderBy(p => p.Index).ToArray();

                var streamDict = new Dictionary<string, Stream>();

                foreach (var item in inputItems)
                {
                    if (item.IsDirectory) continue;
                    var ban = false;

                    foreach (var prefix in banPrefix)
                    {
                        if (item.FileName.StartsWith(prefix))
                        {
                            ban = true;
                            break;
                        }
                    }

                    if (!ban)
                    {
                        foreach (var suffix in banSuffix)
                        {
                            if (item.FileName.EndsWith(suffix))
                            {
                                ban = true;
                                break;
                            }
                        }
                    }

                    if (ban)
                    {
                        Console.WriteLine($"Banned: {item.FileName}");
                        continue;
                    }

                    streamDict.Add(item.FileName, new BridgeStream(1, (long?)item.Size, inputArchive, item.Index));
                }

                ////////////////////

                var outputArchive = new SevenZipCompressor
                {
                    ArchiveFormat = OutArchiveFormat.Zip,
                    CompressionMethod = CompressionMethod.Copy,
                    CompressionMode = CompressionMode.Create,
                };

                outputArchive.FileCompressionStarted += (_, eventArgs) => Console.WriteLine($"EntryStarted:{eventArgs.FileName} ");
                outputArchive.Compressing += (_, eventArgs) => Console.Write($"{eventArgs.PercentDone}% ");
                outputArchive.FileCompressionFinished += (_, _) => Console.WriteLine($"EntryFinished");

                outputArchive.CompressStreamDictionary(streamDict, outputFilePath);

                Console.WriteLine("Process Finished");
            }

            return 0;
        }
    }
}