using anbs_cp.Classes;

using FileSplitter.Shared.Classes;
using FileSplitter.Shared.Enums;

using static System.Console;

namespace FileSplitter.Console.Classes;

/// <summary>
/// Класс для выполнения разбиения, сборки, интерактивного режима
/// </summary>
internal static class Executor
{
    /// <summary>
    /// Вывод прогресса
    /// </summary>
    /// <param name="sender">Вызывающий объект</param>
    /// <param name="args"><see cref="FileSplitterOnProgress"/></param>
    private static void OnProgress (object sender, FileSplitterOnProgress args)
    {
        //Вывод сообщения в консоль
        WriteLine(args.Message);
    }

    /// <summary>
    /// Выполняю разбиение
    /// </summary>
    /// <param name="fileName">Имя файла</param>
    /// <param name="targetDir">Целевая папка с файлами разбиения</param>
    /// <param name="partSize">Размер части</param>
    /// <param name="silent">Тихий режим (без запросов)</param>
    /// <param name="options">Параметры разбиения</param>
    /// <returns>Код возврата</returns>
    public static FsExitCode DoSplit (string fileName, string targetDir, long partSize, bool silent, List<FileSplitOptions> options)
    {
        //Функция прогресса
#pragma warning disable CS8622
        FileSplitterClass.OnProgress += OnProgress;
#pragma warning restore CS8622

        //Если не выбран тихий режим
        if (!silent)
        {
            //- получаю информацию о разбиении
            TargetFileInfo fileInfo = FileSplitterClass.GetSplitFileInfo(fileName, partSize);

            //- спрашиваю пользователя
            WriteLine(Localization.MessageSplitAsk, fileInfo.FileName,
                new FileSizeConverter(Localization.FileSizeStrings).Convert(fileInfo.FileSize),
                BitConverter.ToString(fileInfo.FileHash).Replace("-", "").ToLowerInvariant(),
                fileInfo.SplitCount);

            //- получаю ответ
            string? userInput = ReadLine();

            //- проверяю согласие
            if (userInput == null || userInput.ToLower() != "y")
                //-- и прерываю, если не получил
                return FsExitCode.ecUserAborted;
        }

        //Выполняю разбиение
        return FileSplitterClass.SplitFile(fileName, targetDir, partSize, options.AsReadOnly());
    }

    /// <summary>
    /// Выполняю сборку
    /// </summary>
    /// <param name="infoFileName">Файл информации о разбиении</param>
    /// <param name="targetFileName">Целевой файл</param>
    /// <param name="silent">Тихий режим (без запросов)</param>
    /// <param name="options">Параметры сборки</param>
    /// <returns>Код возврата</returns>
    public static FsExitCode DoJoin (string infoFileName, string targetFileName, bool silent, List<FileJoinOptions> options)
    {
        //Функция прогресса
#pragma warning disable CS8622
        FileSplitterClass.OnProgress += OnProgress;
#pragma warning restore CS8622

        //Если не выбран тихий режим
        if (!silent)
        {
            //- спрашиваю пользователя
            WriteLine(Localization.MessageJoinAsk, targetFileName);

            //- получаю ответ
            string? userInput = ReadLine();

            //- проверяю согласие
            if (userInput == null || userInput.ToLower() != "y")
                //-- и прерываю, если не получил
                return FsExitCode.ecUserAborted;
        }

        //Выполняю объединение
        return FileSplitterClass.JoinFile(infoFileName, targetFileName, options.AsReadOnly());
    }

    public static FsExitCode DoInteractive ()
    {
        //Пользовательский ввод
        string userInput;

        //Цикл получения информации
        do
        {
            //Вывожу приветственный запрос на выбор операции
            WriteLine(Localization.InteractiveStartAsk);

            //Получаю ответ
            userInput = ReadLine() ?? string.Empty;

            //Обработано ли решение
            bool handled = false;

            //Обрабатываем выбор пользователя
            switch (userInput.ToLower())
            {
                //Если пользователь выбрал разбиение
                case "s":
                    {
                        //- то запускаем разбиение
                        FsExitCode splitExitCode = DoSplitInteractive();

                        //- вывожу сообщение
                        WriteLine(Localization.InteractiveOperationFinish, Localization.ExitCodeNames.First(eCode => eCode.Item1 == splitExitCode).Item2);

                        //- указываем на перехват
                        handled = true;
                        break;
                    }
                //Если пользователь указал на выход
                case "e":
                    //- то указываем на перехват
                    handled = true;
                    break;
            }

            //Если решение не обработано
            if (!handled)
                //- то вывожу сообщение
                WriteLine(Localization.InteractiveWrongInput);
        } while (userInput.ToLower() != "e");

        //Закрываю интерактивную операцию
        return FsExitCode.ecAllDone;
    }

    /// <summary>
    /// Интерактивное разбиение файла
    /// </summary>
    /// <returns><see cref="FsExitCode"/></returns>
    public static FsExitCode DoSplitInteractive ()
    {
        //Пользовательский ввод
        string userInput;

        //Обработан ли ввод
        bool isHandled = false;

        /* Имя файла */
        //Выбор имени файла
        do
        {
            //Запрос имени файла
            WriteLine(Localization.InteractiveSplitFileNameAsk);

            //Считываю имя файла
            userInput = ReadLine() ?? string.Empty;

            //Если файл не существует
            if (!File.Exists(userInput))
            {
                //- то запрашиваю действие
                WriteLine(Localization.InteractiveFileNameNotExist);

                //- считываю ответ
                userInput = ReadLine() ?? string.Empty;

                //- если выбрано не повторять
                if (userInput.ToLower() != "y")
                    //-- то прерываю операцию
                    return FsExitCode.ecUserAborted;
            }
            else
            {
                //В противном случае, считаю ввод корректным
                isHandled = true;
            }
        } while (!isHandled);

        //Ввожу переменную с именем файла
        string fileName = userInput;

        //Вывожу информацию о выборе файла
        WriteLine(Localization.InteractiveSplitFileNameResult, fileName);

        /* Целевая папка */

        //Выбираю целевую папку
        WriteLine(Localization.InteractiveSplitTargetDirAsk);

        //Считываю данные
        userInput = ReadLine() ?? string.Empty;

        //Если вместо папки пустое место
        if (string.IsNullOrWhiteSpace(userInput))
            //- то задаю папку имени файла
            userInput = Path.GetDirectoryName(fileName) ?? string.Empty;

        //Ввожу переменную целевой папки
        string targetDir = LikeDelphi.IncludeTrailingBackslash(userInput);

        //Вывожу информацию о выборе целевой папки
        WriteLine(Localization.InteractiveSplitTargetDirResult, targetDir);

        /* Размер части */
        //Ввожу переменную размера части
        long partSize;

        //Создаю конвертер
        FileSizeConverter converter = new(Localization.FileSizeStrings, 1);

        //Устанавливаю перехват в false
        isHandled = false;

        //Выбор размер части
        do
        {
            //Получаю размер исходного файла
            long fileSize = FileExtension.FileSize(fileName);

            //Запрос размера части
            WriteLine(Localization.InteractiveSplitPartSizeAsk);

            //Считываю размер части
            userInput = ReadLine() ?? fileSize.ToString();

            //Задаю размер части
            partSize = TypeConverter.StrToInt64(userInput, fileSize);

            //Запрашиваю согласие на размер части
            WriteLine(Localization.InteractiveSplitPartSizeAsk2, converter.Convert(partSize));

            //Считываю ответ
            userInput = ReadLine() ?? string.Empty;

            //Если согласен, то выхожу из цикла
            if (userInput.ToLower() == "y")
                isHandled = true;
        } while (!isHandled);

        //Вывожу информацию о размере части
        WriteLine(Localization.InteractiveSplitPartSizeResult, converter.Convert(partSize));

        /* Опции разбиения */
        //Ввожу переменную опций разбиения
        List<FileSplitOptions> options = new();

        //Запрос опций разбиения
        WriteLine(Localization.InteractiveSplitOptionsAsk);

        //Считываю опции разбиения
        userInput = (ReadLine() ?? string.Empty).ToLower().Trim();

        //Инициализирую список параметров
        ConsoleParamsParser @params = new(userInput.Split(' '));

        //Проверяю параметры разбиения
        //- отключена ли проверка хэша
        if (@params.HasParam("/NoCheckHash"))
            options.Add(FileSplitOptions.fsoNoCheckHash);
        //- нужно ли удалять исходный файл
        if (@params.HasParam("/DeleteSource"))
            options.Add(FileSplitOptions.fsoDeleteSourceFileAfterSplit);
        //- нужно ли шифровать файл информации
        if (@params.HasParam("/EncryptInfoFile"))
            options.Add(FileSplitOptions.fsoEncryptInfoFile);

        //Вывожу информацию о выборе параметров
        WriteLine(Localization.InteractiveSplitOptionsResult, userInput);

        /* Выполнение разбиения */
        return DoSplit(fileName, targetDir, partSize, false, options);
    }
}