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;


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);
    }
}