using System.Collections.Generic;
using System.IO;
using System.Linq;
using CliWrap;
using System.Threading.Tasks;
using System.Threading;
using System;
using iText.Kernel.Pdf;
using iText.Kernel.Utils;

namespace AsbCloudInfrastructure.Services.DrillingProgram.Convert
{
#nullable enable
    sealed internal class ConvertToPdf
    {
        internal static readonly string[] filesExtensions = { ".xlsx", ".xls", ".ods", ".odt", ".doc", ".docx", ".pdf" };

        private static void MergeFiles(IEnumerable<string> inputFiles, string outFile)
        {
            using var docResult = new PdfDocument(new PdfWriter(outFile));
            var merger = new PdfMerger(docResult);
            
            foreach (var fileName in inputFiles)
            {
                using var doc = new PdfDocument(new PdfReader(fileName));
                merger.Merge(doc, 1, doc.GetNumberOfPages());
                doc.Close();             
            };
            
            docResult.Close();
        }

        private static (string programFile, string programArg) GetOptionsStartupProcess (string inputFileName, string resultFileDir)
        {
            (string programFile, string programArg) startupOptions;
            if (OperatingSystem.IsWindows())
            {
                startupOptions.programFile = "C:\\Program Files\\LibreOffice\\program\\soffice.exe";
                startupOptions.programArg = $"-headless -convert-to pdf {inputFileName} --outdir {resultFileDir}";
                return startupOptions;
            }
            if(OperatingSystem.IsLinux())
            {
                startupOptions.programFile = "/usr/bin/soffice";
                startupOptions.programArg = $"--headless --convert-to pdf {inputFileName} --outdir {resultFileDir}";
                return (startupOptions);
            }

            throw new NotSupportedException ("Вызов процесса в текущей операционной системе не возможен");
        }

        private static async Task StartConvertProcessAsync(string inputFileName, string resultFileDir, CancellationToken token)
        {
            var (programFile, programArg) = GetOptionsStartupProcess(inputFileName, resultFileDir);
            var command = Cli.Wrap(programFile)
                .WithArguments(programArg);
            await command.ExecuteAsync(token);
        }

        public static async Task GetConverteAndMergedFileAsync(IEnumerable<string> files, string resultPath, string convertedFilesDir, CancellationToken token)
        {
            var badFiles = files.Where(f => !filesExtensions.Contains(Path.GetExtension(f)));
            if (badFiles.Any())
            {
                throw new FileFormatException($"Файлы: {string.Join(", ", badFiles)} - неподдерживаемого формата. " +
                    $"Они не могут быть добавлены в список файлов для конвертации и слияния в общий файл программы бурения.");
            }
            var listFiles = files
                .Distinct()
                .Select(f => new
                {
                    inputFile = f,
                    convertedFile = Path.Combine(convertedFilesDir, "pdf", Path.ChangeExtension(Path.GetFileName(f), ".pdf"))
                })
                .ToList();
            foreach (var file in listFiles)
            {
                var fileExt = Path.GetExtension(file.inputFile).ToLower();
                if (fileExt != ".pdf")
                {
                    await StartConvertProcessAsync(file.inputFile, Path.GetDirectoryName(file.convertedFile)!, token);
                }
            }
            MergeFiles(listFiles.Select(c => c.convertedFile), resultPath);
            Directory.Delete(Path.Combine(convertedFilesDir, "pdf"), true);
        }
    }
#nullable disable
}