using System.Collections.ObjectModel;
using System.Text.Json;
using View_by_Distance.Shared.Models;

namespace View_by_Distance.Instance.Models;

/// <summary>
// List<string>
/// </summary>
internal class F_Random
{

    private readonly Configuration _Configuration;
    private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;

    internal F_Random(Configuration configuration)
    {
        _Configuration = configuration;
        _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = false };
    }

    public override string ToString()
    {
        string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
        return result;
    }

    private static ReadOnlyDictionary<string, List<string>> GetDayToRelativePaths(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection, string dateFormat, string immichOwnerId, string immichRoot, Dictionary<string, ImmichAsset> immichAssets, ReadOnlyDictionary<int, List<long>> idToPersonKeys)
    {
        Dictionary<string, List<string>> results = [];
        string key;
        DateTime dateTime;
        List<long>? personKeys;
        ImmichAsset? immichAsset;
        List<string>? relativePaths;
        bool immichAssetsCountIsZero = immichAssets.Count == 0;
        foreach (Mapping mapping in distinctValidImageMappingCollection)
        {
            if (mapping.MappingFromItem.FilePath.DirectoryFullPath is null || mapping.MappingFromPerson is null)
                continue;
            if (!idToPersonKeys.TryGetValue(mapping.MappingFromItem.Id, out personKeys))
                continue;
            if (Shared.Models.Stateless.Methods.IPersonBirthday.IsCounterPersonYear(mapping.MappingFromPerson.PersonKey))
                continue;
            if (!personKeys.Contains(mapping.MappingFromPerson.PersonKey))
                continue;
            dateTime = new(mapping.MappingFromPerson.PersonKey);
            key = dateTime.ToString(dateFormat);
            if (!results.TryGetValue(key, out relativePaths))
            {
                results.Add(key, []);
                if (!results.TryGetValue(key, out relativePaths))
                    throw new Exception();
            }
            if (immichAssetsCountIsZero)
                relativePaths.Add(mapping.MappingFromItem.RelativePath);
            else
            {
                if (!immichAssets.TryGetValue($"{immichRoot}{mapping.MappingFromItem.RelativePath}", out immichAsset))
                    continue;
                if (!immichAsset.Path.Contains(immichOwnerId))
                    continue;
                relativePaths.Add(immichAsset.Path.Split(immichOwnerId)[1]);
            }
        }
        return results.AsReadOnly();
    }

    private static Dictionary<string, ImmichAsset> GetImmichAssets(string immichAssetsFile)
    {
        Dictionary<string, ImmichAsset> results = [];
        if (!string.IsNullOrEmpty(immichAssetsFile) && File.Exists(immichAssetsFile))
        {
            string json = File.ReadAllText(immichAssetsFile);
            ImmichAsset[]? immichAssets = JsonSerializer.Deserialize(json, ImmichAssetCollectionSourceGenerationContext.Default.ImmichAssetArray);
            if (immichAssets is not null)
            {
                foreach (ImmichAsset immichAsset in immichAssets)
                    results.Add(immichAsset.OriginalPath, immichAsset);
            }
        }
        return results;
    }

    internal void Random(Property.Models.Configuration configuration, string immichAssetsFile, string immichOwnerId, string immichRoot, int radomUseBirthdayMinimum, string[] validKeyWordsToIgnoreInRandom, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyDictionary<int, Identifier> splatNineIdentifiers, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
    {
        string key;
        string json;
        string jsonFile;
        Random random = new();
        List<string>? collection;
        ImmichAsset? immichAsset;
        string dateFormat = "MM-dd";
        List<string> relativePaths = [];
        List<int> distinctCollection = [];
        DateTime dateTime = new(2024, 1, 1); //Leap year
        Dictionary<string, ImmichAsset> immichAssets = GetImmichAssets(immichAssetsFile);
        int[] splatNineIdentifiersKeys = splatNineIdentifiers.Select(l => l.Key).ToArray();
        ReadOnlyDictionary<int, List<long>> idToPersonKeys = Map.Models.Stateless.Methods.IMapLogic.GetIdToPersonKeys(personKeyToIds);
        ReadOnlyDictionary<string, List<string>> dayToRelativePaths = GetDayToRelativePaths(distinctValidImageMappingCollection, dateFormat, immichOwnerId, immichRoot, immichAssets, idToPersonKeys);
        string fRandomCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(F_Random), "[]");
        string[] files = Directory.GetFiles(fRandomCollectionDirectory, "*", SearchOption.TopDirectoryOnly);
        foreach (string file in files)
            File.Delete(file);
        bool immichAssetsCountIsZero = immichAssets.Count == 0;
        foreach (Mapping mapping in distinctValidImageMappingCollection)
        {
            if (mapping.MappingFromItem.IsArchive is not null && mapping.MappingFromItem.IsArchive.Value)
                continue;
            if (distinctCollection.Contains(mapping.MappingFromItem.Id))
                continue;
            if (mapping.MappingFromItem.FilePath.DirectoryFullPath is null)
                continue;
            if (!splatNineIdentifiersKeys.Contains(mapping.MappingFromItem.Id))
                continue;
            if (mapping.MappingFromItem.Keywords is not null && mapping.MappingFromItem.Keywords.Any(l => validKeyWordsToIgnoreInRandom.Contains(l)))
                continue;
            if (immichAssetsCountIsZero)
                relativePaths.Add(mapping.MappingFromItem.RelativePath);
            else
            {
                if (!immichAssets.TryGetValue($"{immichRoot}{mapping.MappingFromItem.RelativePath}", out immichAsset))
                    continue;
                if (!immichAsset.Path.Contains(immichOwnerId))
                    continue;
                relativePaths.Add(immichAsset.Path.Split(immichOwnerId)[1]);
            }
            distinctCollection.Add(mapping.MappingFromItem.Id);
        }
        if (relativePaths.Count > 0)
        {
            for (int i = 0; i < 366; i++)
            {
                random = new(i);
                key = dateTime.AddDays(i).ToString(dateFormat);
                if (dayToRelativePaths.TryGetValue(key, out collection) && collection.Count > radomUseBirthdayMinimum)
                    collection = (from l in collection orderby random.NextDouble() select l).ToList();
                else
                    collection = (from l in relativePaths orderby random.NextDouble() select l).ToList();
                jsonFile = Path.Combine(fRandomCollectionDirectory, $"{key}.json");
                json = JsonSerializer.Serialize(collection, _WriteIndentedJsonSerializerOptions);
                _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: false, compareBeforeWrite: false);
                if (!_Configuration.SaveFullYearOfRandomFiles)
                    break;
            }
        }
    }

}