using Microsoft.Extensions.Configuration;
using Phares.Shared;
using Serilog;
using ShellProgressBar;
using System.Text;
using View_by_Distance.Metadata.Models;
using View_by_Distance.Set.Created.Date.Models;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Methods;

namespace View_by_Distance.Set.Created.Date;

public class SetCreatedDate
{

    private record Record(FileHolder FileHolder, bool OriginalSet, DateTime DateTime);

    private readonly AppSettings _AppSettings;
    private readonly string _WorkingDirectory;
    private readonly Configuration _Configuration;
    private readonly IsEnvironment _IsEnvironment;
    private readonly IConfigurationRoot _ConfigurationRoot;
    private readonly IReadOnlyDictionary<string, string[]> _FileGroups;
    private readonly Property.Models.Configuration _PropertyConfiguration;

    public SetCreatedDate(List<string> args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console)
    {
        if (isSilent)
        { }
        if (console is null)
        { }
        _AppSettings = appSettings;
        _IsEnvironment = isEnvironment;
        _WorkingDirectory = workingDirectory;
        _ConfigurationRoot = configurationRoot;
        ILogger? log = Log.ForContext<SetCreatedDate>();
        Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
        string[] directories = new string[] { propertyConfiguration.ResultContent };
        _FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, appSettings.CopyTo, directories);
        Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration);
        _PropertyConfiguration = propertyConfiguration;
        _Configuration = configuration;
        propertyConfiguration.Update();
        log.Information(propertyConfiguration.RootDirectory);
        Verify();
        List<string> lines = SetCreatedDateFilesInDirectories(log);
        File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines);
        if (lines.Count == 0)
            _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory);
    }

    private void Verify()
    {
        if (_AppSettings is null)
        { }
        if (_IsEnvironment is null)
        { }
        if (_Configuration is null)
        { }
        if (_ConfigurationRoot is null)
        { }
        if (_WorkingDirectory is null)
        { }
        if (_PropertyConfiguration is null)
        { }
    }

    private List<Record> GetRecords(ProgressBar progressBar, ASCIIEncoding asciiEncoding, B_Metadata metadata, string[] files)
    {
        List<Record> results = new();
        int? id;
        string? message;
        DateTime[] dateTimes;
        FileHolder fileHolder;
        bool isIgnoreExtension;
        DateTime? dateTimeOriginal;
        bool isValidImageFormatExtension;
        foreach (string file in files)
        {
            progressBar.Tick();
            fileHolder = new(file);
            if (fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null)
                continue;
            if (_PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered))
                continue;
            isValidImageFormatExtension = _PropertyConfiguration.ValidImageFormatExtensions.Contains(fileHolder.ExtensionLowered);
            isIgnoreExtension = isValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered);
            if (isIgnoreExtension || !isValidImageFormatExtension)
                continue;
            (dateTimeOriginal, dateTimes, id, message) = Property.Models.Stateless.IProperty.Get(_PropertyConfiguration.PopulatePropertyId, metadata, fileHolder, isIgnoreExtension, isValidImageFormatExtension, asciiEncoding);
            if (dateTimeOriginal is null)
                results.Add(new(fileHolder, false, dateTimes.Min()));
            else
                results.Add(new(fileHolder, true, dateTimeOriginal.Value));
        }
        return results;
    }

    private List<Record> GetToDoCollection(ProgressBar progressBar, List<string[]> filesCollection)
    {
        List<Record> results = new();
        int minutes;
        Record[] records;
        List<Record> unordered;
        ASCIIEncoding asciiEncoding = new();
        B_Metadata metadata = new(_PropertyConfiguration);
        List<Record[]> collections = new();
        foreach (string[] files in filesCollection)
        {
            minutes = 0;
            unordered = GetRecords(progressBar, asciiEncoding, metadata, files);
            records = (from l in unordered orderby l.DateTime, l.FileHolder.Name.Length, l.FileHolder.Name select l).ToArray();
            foreach (Record record in records)
            {
                if (record.DateTime == record.FileHolder.CreationTime)
                    continue;
                if (record.OriginalSet)
                    results.Add(new(record.FileHolder, record.OriginalSet, record.DateTime));
                else
                {
                    minutes += 1;
                    results.Add(new(record.FileHolder, record.OriginalSet, record.DateTime.AddMinutes(minutes)));
                }
            }
        }
        return results;
    }

    private static List<string> SetCreatedDateForeach(ProgressBar progressBar, List<Record> toDoCollection)
    {
        List<string> results = new();
        foreach (Record record in toDoCollection)
        {
            progressBar.Tick();
            results.Add(record.FileHolder.NameWithoutExtension);
            try
            { File.SetCreationTime(record.FileHolder.FullName, record.DateTime); }
            catch (Exception) { }
        }
        return results;
    }

    private List<string> SetCreatedDateFilesInDirectories(ILogger log)
    {
        List<string> results = new();
        ProgressBar progressBar;
        ConsoleKey? consoleKey = null;
        const string fileSearchFilter = "*";
        string message = nameof(SetCreatedDate);
        const string directorySearchFilter = "*";
        List<string[]> filesCollection = Shared.Models.Stateless.Methods.IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter);
        int count = filesCollection.Select(l => l.Length).Sum();
        ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
        progressBar = new(count, message, options);
        List<Record> toDoCollection = GetToDoCollection(progressBar, filesCollection);
        progressBar.Dispose();
        log.Information($"Ready to set created date {toDoCollection.Count} file(s)?");
        for (int y = 0; y < int.MaxValue; y++)
        {
            log.Information("Press \"Y\" key to set created date file(s), \"N\" key to log file(s) or close console to not set created date files");
            consoleKey = System.Console.ReadKey().Key;
            if (consoleKey is ConsoleKey.Y or ConsoleKey.N)
                break;
        }
        log.Information(". . .");
        if (consoleKey is null || consoleKey.Value != ConsoleKey.Y)
            log.Information("Nothing set!");
        else
        {
            progressBar = new(count, message, options);
            results.AddRange(SetCreatedDateForeach(progressBar, toDoCollection));
            progressBar.Dispose();
            log.Information("Done setting created date");
        }
        return results;
    }

}