namespace View_by_Distance.Shared.Models.Stateless.Methods;

internal abstract class PersonContainer
{

    private static string[] GetFiles(int locationDigits, string facesFileNameExtension, string personDisplayDirectory)
    {
        string[] results = Directory.GetFiles(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly);
        int? id;
        string checkFile;
        string? checkDirectory;
        int? normalizedPixelPercentage;
        foreach (string personDisplayDirectoryAllFile in results)
        {
            if (personDisplayDirectoryAllFile.EndsWith(".lnk"))
                continue;
            (id, normalizedPixelPercentage, _) = IMapping.GetReversedDeterministicHashCodeKey(locationDigits, facesFileNameExtension, personDisplayDirectoryAllFile);
            if (id is not null && normalizedPixelPercentage is not null && !personDisplayDirectoryAllFile.EndsWith(".json"))
                continue;
            checkDirectory = Path.GetDirectoryName(personDisplayDirectoryAllFile);
            if (string.IsNullOrEmpty(checkDirectory))
                continue;
            checkDirectory = Path.Combine(checkDirectory, "_ Invalid");
            if (!Directory.Exists(checkDirectory))
                _ = Directory.CreateDirectory(checkDirectory);
            checkFile = Path.Combine(checkDirectory, Path.GetFileName(personDisplayDirectoryAllFile));
            if (File.Exists(checkFile))
                File.Delete(personDisplayDirectoryAllFile);
            else
                File.Move(personDisplayDirectoryAllFile, checkFile);
        }
        results = Directory.GetFiles(personDisplayDirectory, "*", SearchOption.AllDirectories);
        return results;
    }

    private static List<(long?, Models.PersonContainer)> GetPersonContainersCollections(int locationDigits, string personBirthdayFormat, string facesFileNameExtension, char[] chars, string personDisplayDirectory, string personDisplayDirectoryName, string[] personKeyDirectories, int? approximateYears, List<Models.PersonBirthday> collections)
    {
        List<(long?, Models.PersonContainer)> results = new();
        long personKey;
        string[] segments;
        const int zero = 0;
        Models.Person person;
        string personKeyFormatted;
        Models.PersonBirthday? personBirthday;
        Models.PersonContainer personContainer;
        Models.PersonBirthday[] personBirthdays = collections.OrderByDescending(l => l.Value).ToArray();
        string[] personDisplayDirectoryAllFiles = GetFiles(locationDigits, facesFileNameExtension, personDisplayDirectory);
        foreach (string personKeyDirectory in personKeyDirectories)
        {
            personKeyFormatted = Path.GetFileName(personKeyDirectory);
            personBirthday = IPersonBirthday.GetPersonBirthday(personBirthdayFormat, personKeyFormatted);
            if (personBirthday is null)
                continue;
            personKey = personBirthdays[zero].Value.Ticks;
            segments = personDisplayDirectoryName.Split(chars);
            person = IPerson.GetPerson(personKey, segments);
            personContainer = new(approximateYears, person, personBirthdays, personDisplayDirectoryAllFiles, personDisplayDirectoryName, personKey);
            results.Add(new(personKey, personContainer));
        }
        return results;
    }

    private static Models.PersonContainer GetPersonContainer(int locationDigits, string facesFileNameExtension, string personDisplayDirectory, string personDisplayDirectoryName, int? approximateYears)
    {
        Models.PersonContainer result;
        string[] personDisplayDirectoryAllFiles = GetFiles(locationDigits, facesFileNameExtension, personDisplayDirectory);
        result = new(approximateYears, personDisplayDirectoryAllFiles, personDisplayDirectoryName);
        return result;
    }

    private static List<(long?, Models.PersonContainer)> GetPersonContainersGroup(int locationDigits, string personBirthdayFormat, string facesFileNameExtension, char[] chars, string[] personDisplayDirectories)
    {
        List<(long?, Models.PersonContainer)> results = new();
        int? approximateYears;
        string[] personKeyDirectories;
        string? personDisplayDirectoryName;
        Models.PersonContainer personContainer;
        List<Models.PersonBirthday> collections;
        foreach (string personDisplayDirectory in personDisplayDirectories)
        {
            personDisplayDirectoryName = Path.GetFileName(personDisplayDirectory);
            if (string.IsNullOrEmpty(personDisplayDirectoryName))
                continue;
            approximateYears = Age.GetApproximateYears(personDisplayDirectoryName, chars);
            personKeyDirectories = Directory.GetDirectories(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly);
            collections = PersonBirthday.GetPersonBirthdays(personBirthdayFormat, personKeyDirectories, personDisplayDirectory);
            if (collections.Any())
                results.AddRange(GetPersonContainersCollections(locationDigits, personBirthdayFormat, facesFileNameExtension, chars, personDisplayDirectory, personDisplayDirectoryName, personKeyDirectories, approximateYears, collections));
            else
            {
                personContainer = GetPersonContainer(locationDigits, facesFileNameExtension, personDisplayDirectory, personDisplayDirectoryName, approximateYears);
                results.Add(new(null, personContainer));
            }
        }
        return results;
    }

    private static Models.PersonContainer[] GetPersonContainersGroups(int locationDigits, string personBirthdayFormat, string facesFileNameExtension, char[] chars, string[] groupDirectories)
    {
        Models.PersonContainer[] results;
        const int zero = 0;
        string groupDirectoryName;
        string[] personDisplayDirectories;
        List<(long?, Models.PersonContainer)> collection;
        List<(long? PersonKey, Models.PersonContainer PersonContainer)> personContainers = new();
        foreach (string groupDirectory in groupDirectories)
        {
            groupDirectoryName = Path.GetFileName(groupDirectory);
            if (!chars.Contains(groupDirectoryName[zero]))
                continue;
            personDisplayDirectories = Directory.GetDirectories(groupDirectory, "*", SearchOption.TopDirectoryOnly);
            collection = GetPersonContainersGroup(locationDigits, personBirthdayFormat, facesFileNameExtension, chars, personDisplayDirectories);
            personContainers.AddRange(collection);
        }
        results = (from l in personContainers orderby l.PersonKey is not null, l.PersonKey select l.PersonContainer).ToArray();
        return results;
    }

    internal static Models.PersonContainer[] GetPersonContainers(Properties.IStorage storage, int locationDigits, string personBirthdayFormat, string facesFileNameExtension)
    {
        Models.PersonContainer[] results;
        char[] chars = IAge.GetChars();
        string a2PeopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}");
        if (!Directory.Exists(a2PeopleSingletonDirectory))
            _ = Directory.CreateDirectory(a2PeopleSingletonDirectory);
        string a2PeopleSingletonDirectoryChar;
        foreach (char @char in chars)
        {
            a2PeopleSingletonDirectoryChar = Path.Combine(a2PeopleSingletonDirectory, @char.ToString());
            if (!Directory.Exists(a2PeopleSingletonDirectoryChar))
                _ = Directory.CreateDirectory(a2PeopleSingletonDirectoryChar);
        }
        string[] groupDirectories = Directory.GetDirectories(a2PeopleSingletonDirectory, "*", SearchOption.TopDirectoryOnly);
        if (!groupDirectories.Any())
            results = Array.Empty<Models.PersonContainer>();
        else
            results = GetPersonContainersGroups(locationDigits, personBirthdayFormat, facesFileNameExtension, chars, groupDirectories);
        return results;
    }

}