using System.Collections.ObjectModel;
using View_by_Distance.Shared.Models.Properties;

namespace View_by_Distance.Shared.Models.Stateless.Methods;

internal abstract class FilePair
{

    internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
    {
        ReadOnlyCollection<Models.FilePair> results;
        ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
        results = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
        return results;
    }

    internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles)
    {
        List<Models.FilePair>? results = null;
        int renamed;
        const bool useCeilingAverage = true;
        ReadOnlyCollection<string[]>? jsonFilesCollection = null;
        IReadOnlyDictionary<int, List<FilePath>>? compareFileNamesToFiles = null;
        for (int i = 0; i < fileNamesToFiles.Count; i++)
        {
            renamed = 0;
            jsonFilesCollection = XDirectory.GetFilesCollection(jsonGroupDirectory, directorySearchFilter, extension, useCeilingAverage);
            renamed += LookForAbandoned(propertyConfiguration, jsonFilesCollection, fileNamesToFiles, extension);
            if (renamed > 0)
                continue;
            compareFileNamesToFiles = GetKeyValuePairs(propertyConfiguration, jsonFilesCollection);
            results = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
            renamed += XDirectory.MaybeMove(propertyConfiguration, results, jsonGroupDirectory, extension);
            if (renamed == 0)
                break;
            if (i > 10)
                throw new NotImplementedException();
        }
        if (results is null || jsonFilesCollection is null || compareFileNamesToFiles is null)
            throw new NullReferenceException(nameof(results));
        return results.AsReadOnly();
    }

    private static int LookForAbandoned(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string extension)
    {
        int result;
        bool check;
        bool moved = false;
        List<string> renameCollection = [];
        foreach (string[] files in jsonFilesCollection)
        {
            if (files.Length == 0)
                continue;
            check = AnyMoved(propertyConfiguration, fileNamesToFiles, extension, renameCollection, files);
            if (!moved && check)
                moved = true;
        }
        if (renameCollection.Count > 0)
            XDirectory.MoveFiles(renameCollection, "{}", "{abd}");
        result = renameCollection.Count;
        if (moved && result == 0)
            result = 1;
        return result;
    }

    private static bool AnyMoved(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
    {
        bool result = false;
        string checkFile;
        string directory;
        FilePath filePath;
        string fileNameWith;
        string checkDirectory;
        string directoryName;
        List<FilePath>? collection;
        Models.FileHolder fileHolder;
        List<string> directoryNames = [];
        foreach (string file in files)
        {
            if (!file.EndsWith(extension))
                throw new Exception();
            fileHolder = IFileHolder.Get(file);
            if (!fileHolder.Exists)
                continue;
            filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
            if (filePath.Id is null)
                continue;
            if (!fileNamesToFiles.TryGetValue(filePath.Id.Value, out collection))
                renameCollection.Add(file);
            else
            {
                directoryNames.Clear();
                directoryName = Path.GetFileName(filePath.DirectoryFullPath) ?? throw new Exception();
                foreach (FilePath f in collection)
                    directoryNames.Add(Path.GetFileName(f.DirectoryFullPath) ?? throw new Exception());
                if (directoryNames.Count == 0 || directoryNames.Distinct().Count() != 1)
                    continue;
                if (directoryName != directoryNames[0])
                {
                    directory = Path.GetDirectoryName(filePath.DirectoryFullPath) ?? throw new Exception();
                    checkDirectory = Path.Combine(directory, directoryNames[0]);
                    if (!Directory.Exists(checkDirectory))
                        _ = Directory.CreateDirectory(checkDirectory);
                    fileNameWith = collection.Count > 1 ? filePath.Name : $"{collection[0].Name}{extension}";
                    checkFile = Path.Combine(checkDirectory, fileNameWith);
                    if (!result)
                        result = true;
                    if (!File.Exists(checkFile))
                        File.Move(file, checkFile);
                    else
                    {
                        if (new FileInfo(file).LastWriteTime > new FileInfo(checkFile).LastWriteTime)
                            File.Delete(file);
                        else
                            File.Move(file, checkFile, true);
                    }
                }
            }
        }
        return result;
    }

    private static ReadOnlyDictionary<int, List<FilePath>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
    {
        Dictionary<int, List<FilePath>> results = [];
        List<FilePath>? collection;
        FilePath filePath;
        Models.FileHolder fileHolder;
        foreach (string[] files in filesCollection)
        {
            foreach (string file in files)
            {
                fileHolder = IFileHolder.Get(file);
                if (!fileHolder.Exists)
                    continue;
                filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
                if (filePath.Id is null)
                    continue;
                if (!results.TryGetValue(filePath.Id.Value, out collection))
                {
                    results.Add(filePath.Id.Value, []);
                    if (!results.TryGetValue(filePath.Id.Value, out collection))
                        throw new Exception();
                }
                collection.Add(filePath);
            }
        }
        return new(results);
    }

}