using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using CliWrap;
using System.Threading.Tasks;
using System.Threading;
using System;

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 stream = new FileStream(outFile, FileMode.Create);
            using var doc = new Document();
            using var pdf = new PdfCopy(doc, stream);
            doc.Open();
            var inputFilesList = inputFiles.ToList();
            foreach (var file in inputFilesList)
            {
                var reader = new PdfReader(file);
                for (int i = 0; i < reader.NumberOfPages; i++)
                {
                    pdf.AddPage(pdf.GetImportedPage(reader, i + 1));
                }
                pdf.FreeReader(reader);
                reader.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
}