using Microsoft.Extensions.Configuration;
using Phares.Shared;
using View_by_Distance.Not.Copy.Copy.Models;
using View_by_Distance.Property.Models;
using View_by_Distance.Shared.Models.Methods;

namespace View_by_Distance.Not.Copy.Copy;

public class NotCopyCopy
{

    private readonly Serilog.ILogger? _Log;
    private readonly AppSettings _AppSettings;
    private readonly IsEnvironment _IsEnvironment;
    private readonly Models.Configuration _Configuration;

    public NotCopyCopy(List<string> args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console)
    {
        if (isSilent)
        { }
        if (args is null)
        { }
        if (console is null)
        { }
        _AppSettings = appSettings;
        _IsEnvironment = isEnvironment;
        _Log = Serilog.Log.ForContext<NotCopyCopy>();
        Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
        Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration);
        _Log.Information(propertyConfiguration.RootDirectory);
        Property.Models.Configuration.Verify(propertyConfiguration, requireExist: true);
        Verify(configuration);
        bool reverse = false;
        string outputExtension = ".jpg";
        _Configuration = configuration;
        if (!_IsEnvironment.Development)
            throw new Exception("This program only allows development environments!");
        A_Property propertyLogic = GetPropertyLogic(reverse, outputExtension);
        propertyConfiguration.ChangeRootDirectory(configuration.CompareSource);
        (_, _, _, Shared.Models.Container[] compareContainers) = Property.Models.Stateless.Container.GetContainers(propertyConfiguration, propertyLogic);
        propertyConfiguration.ChangeRootDirectory(configuration.SelectedSource);
        (_, _, _, Shared.Models.Container[] selectedContainers) = Property.Models.Stateless.Container.GetContainers(propertyConfiguration, propertyLogic);
        if (compareContainers.Length == selectedContainers.Length)
            throw new Exception();
        string directoryName;
        List<string> distinct = new();
        List<Property.Models.DirectoryInfo> compareSourceGroupCollection = new();
        List<Property.Models.DirectoryInfo> selectedSourceGroupCollection = new();
        List<(string Source, string[] Destination)> copyCollection = GetCopyCollection(compareSourceGroupCollection, selectedSourceGroupCollection);
        foreach ((string source, string[] destination) in copyCollection)
        {
            directoryName = Path.Combine(destination.Take(destination.Length - 1).ToArray());
            if (distinct.Contains(directoryName))
                continue;
            distinct.Add(directoryName);
            if (!Directory.Exists(directoryName))
                _ = Directory.CreateDirectory(directoryName);
        }
        _Log.Information($"Ready to copy {copyCollection.Count} file(s)?");
        for (int y = 0; y < int.MaxValue; y++)
        {
            _Log.Information("Press \"Y\" key to to copy file(s)");
            if (Console.ReadKey().Key == ConsoleKey.Y)
                break;
        }
        _Log.Information(". . .");
        int copied = 0;
        string fullFileName;
        foreach ((string source, string[] destination) in copyCollection)
        {
            if (copied % 500 == 0)
                _Log.Information($"{copied})");
            fullFileName = Path.Combine(destination);
            if (File.Exists(fullFileName))
                continue;
            File.Copy(source, fullFileName);
            copied += 1;
        }
        _Log.Information($"{copied} file(s) copied");
        for (int y = 0; y < int.MaxValue; y++)
        {
            _Log.Information("Press \"Y\" key to continue or close console");
            if (Console.ReadKey().Key == ConsoleKey.Y)
                break;
        }
        _Log.Information(". . .");
    }

    private static void Verify(Models.Configuration configuration)
    {
        if (Path.GetPathRoot(configuration.SelectedSource) == configuration.SelectedSource)
            throw new NullReferenceException(nameof(configuration.SelectedSource));
        if (string.IsNullOrEmpty(configuration.CompareSource) || !Directory.Exists(configuration.CompareSource))
            throw new NullReferenceException(nameof(configuration.CompareSource));
        if (string.IsNullOrEmpty(configuration.EmptyDestination) || Directory.Exists(configuration.EmptyDestination))
            throw new NullReferenceException(nameof(configuration.EmptyDestination));
        if (string.IsNullOrEmpty(configuration.SelectedSource) || !Directory.Exists(configuration.SelectedSource))
            throw new NullReferenceException(nameof(configuration.SelectedSource));
        if (configuration.SelectedSource.Length != configuration.CompareSource.Length)
            throw new NullReferenceException(nameof(configuration.SelectedSource));
    }

    private A_Property GetPropertyLogic(bool reverse, string outputExtension)
    {
        A_Property result;
        if (_Configuration?.PropertyConfiguration is null)
            throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
        result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, outputExtension, reverse);
        return result;
    }

    private List<(string Source, string[] Destination)> GetCopyCollection(List<Property.Models.DirectoryInfo> compareSourceGroupCollection, List<Property.Models.DirectoryInfo> selectedSourceGroupCollection)
    {
        List<(string Source, string[] Destination)> results = new();
        if (_Configuration?.PropertyConfiguration is null)
            throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration));
        string key;
        string fileName;
        string[] directoryNames;
        string destinationDirectory;
        Shared.Models.Property? property;
        List<string> destinationCollection;
        string filteredSourceDirectoryFile;
        Dictionary<string, Shared.Models.Property> keyValuePairs = new();
        foreach (Property.Models.DirectoryInfo group in compareSourceGroupCollection)
        {
            for (int i = 0; i < group.SourceDirectoryFileHolderCollection.Length; i++)
            {
                property = group.PropertyCollection[i];
                if (property is null)
                    continue;
                key = string.Concat(group.SourceDirectory[_Configuration.CompareSource.Length..], Path.GetFileName(group.FilteredSourceDirectoryFiles[i]));
                keyValuePairs.Add(key, property);
            }
        }
        foreach (Property.Models.DirectoryInfo group in selectedSourceGroupCollection)
        {
            for (int i = 0; i < group.SourceDirectoryFileHolderCollection.Length; i++)
            {
                destinationCollection = new();
                property = group.PropertyCollection[i];
                if (property is null)
                    continue;
                filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i];
                fileName = Path.GetFileName(filteredSourceDirectoryFile);
                key = string.Concat(group.SourceDirectory[_Configuration.SelectedSource.Length..], fileName);
                if (keyValuePairs.ContainsKey(key) && keyValuePairs[key].LastWriteTime == property.LastWriteTime)
                    continue;
                destinationDirectory = string.Concat(_Configuration.EmptyDestination, group.SourceDirectory[_Configuration.SelectedSource.Length..]);
                directoryNames = Shared.Models.Stateless.Methods.IPath.GetDirectoryNames(destinationDirectory);
                destinationCollection.AddRange(directoryNames);
                destinationCollection.Add(fileName);
                results.Add(new(filteredSourceDirectoryFile, destinationCollection.ToArray()));
            }
        }
        return results;
    }

}