using System.Text.Json;
using System.Text.Json.Serialization;
using View_by_Distance.Shared.Models.Methods;

namespace View_by_Distance.Instance.Models;

/// <summary>
// G_Index && G_Index[]
/// </summary>
public class G_Index : Shared.Models.Properties.IIndex, IIndex
{

    private readonly Serilog.ILogger? _Log;
    private readonly Configuration _Configuration;
    private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;

    protected DateTime? _DateTime;
    protected int? _Index;
    protected List<string> _RelativePaths;
    public DateTime? DateTime => _DateTime;
    public int? Index => _Index;
    public List<string> RelativePaths => _RelativePaths;

#nullable disable
    [JsonConstructor]
    public G_Index(DateTime? dateTime, int? index, List<string> relativePaths)
    {
        _DateTime = dateTime;
        _Index = index;
        _RelativePaths = relativePaths;
    }

    internal G_Index()
    {
        _DateTime = null;
        _Index = null;
        _RelativePaths = new();
    }

    internal G_Index(Configuration configuration)
    {
        _Configuration = configuration;
        _Log = Serilog.Log.ForContext<G_Index>();
        _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
    }

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

    private G_Index GetIndexInfo(FileInfo fileInfo, List<string> parseExceptions)
    {
        G_Index result;
        List<int> indices = new();
        string json = File.ReadAllText(fileInfo.FullName);
        try
        {
            result = JsonSerializer.Deserialize<G_Index>(json);
        }
        catch (Exception)
        {
            result = null;
            parseExceptions.Add(nameof(G_Index));
        }
        if (_Configuration.MappedMaxIndex.HasValue && result.Index.HasValue && _Configuration.MappedMaxIndex.Value < result.Index.Value)
        {
            result = null;
            File.Delete(fileInfo.FullName);
        }
        else if (result.Index is null)
            result = null;
        return result;
    }

    private void WriteNeeded(List<int> indices, List<Tuple<List<string>, string, Shared.Models.Property>> neededTuples)
    {
        string json;
        DateTime dateTime;
        Shared.Models.Property property;
        G_Index indexInfo;
        int maxIndexPlusOne;
        DateTime?[] dateTimes;
        if (indices.Any())
            maxIndexPlusOne = indices.Max() + 1;
        else
        {
            maxIndexPlusOne = 1000000;
            throw new Exception("Are you sure exception. Use debugger to step over.");
        }
        foreach (Tuple<List<string>, string, Shared.Models.Property> tuple in neededTuples)
        {
            maxIndexPlusOne += 1;
            property = tuple.Item3;
            dateTimes = new DateTime?[] { property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp };
            dateTime = (from l in dateTimes where l.HasValue select l.Value).Min();
            indexInfo = new(dateTime, maxIndexPlusOne, tuple.Item1);
            json = JsonSerializer.Serialize(indexInfo, _WriteIndentedJsonSerializerOptions);
            if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(tuple.Item2, json, updateDateWhenMatches: true, compareBeforeWrite: true))
                continue;
        }
    }

    private void WriteGroup(Property.Models.Configuration configuration, string outputResolution, List<Tuple<string, Dictionary<int, G_Index>>> indexInfoTuples)
    {
        string json;
        G_Index[] indices;
        List<string> directoryInfoCollection;
        foreach (Tuple<string, Dictionary<int, G_Index>> tuple in indexInfoTuples)
        {
            indices = (from l in tuple.Item2 select l.Value).ToArray();
            directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, tuple.Item1, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: string.Empty, collectionDescription: "Unknown A");
            json = JsonSerializer.Serialize(indices, _WriteIndentedJsonSerializerOptions);
            if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(string.Concat(directoryInfoCollection[0].Replace("<>", "[]"), ".json"), json, updateDateWhenMatches: true, compareBeforeWrite: true))
                continue;
        }
    }

    private void AppendTSV(Property.Models.Configuration configuration, string outputResolution, Dictionary<string, List<Tuple<string, Shared.Models.Property>>> filePropertiesKeyValuePairs)
    {
        Shared.Models.Property property;
        DateTime?[] dateTimes;
        DateTime? maximumDateTime;
        DateTime? minimumDateTime;
        List<string> directoryInfoCollection;
        long ticks = System.DateTime.Now.Ticks;
        foreach (KeyValuePair<string, List<Tuple<string, Shared.Models.Property>>> tuples in filePropertiesKeyValuePairs)
        {
            maximumDateTime = null;
            minimumDateTime = null;
            foreach (Tuple<string, Shared.Models.Property> tuple in tuples.Value)
            {
                property = tuple.Item2;
                dateTimes = new DateTime?[] { maximumDateTime, minimumDateTime, property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp };
                maximumDateTime = (from l in dateTimes where l.HasValue select l.Value).Max();
                minimumDateTime = (from l in dateTimes where l.HasValue select l.Value).Min();
            }
            directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, tuples.Key, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: "Unkown B", collectionDescription: string.Empty);
        }
    }

    internal void SetIndex(Property.Models.Configuration configuration, string outputResolution)
    {
        Dictionary<string, List<Tuple<string, Shared.Models.Property>>> filePropertiesKeyValuePairs = new();
        FileInfo fileInfo;
        G_Index indexInfo;
        string parentCheck;
        List<int> indices = new();
        Dictionary<int, G_Index> valuePairs;
        List<string> directoryInfoCollection;
        List<string> parseExceptions = new();
        List<Tuple<List<string>, string, Shared.Models.Property>> neededTuples = new();
        List<Tuple<string, Dictionary<int, G_Index>>> indexInfoTuples = new();
        for (short i = 0; i < short.MaxValue; i++)
        {
            if (i != 0)
            {
                if (!neededTuples.Any() && !parseExceptions.Any())
                    break;
                indices.Clear();
                indexInfoTuples.Clear();
                parseExceptions.Clear();
            }
            neededTuples.Clear();
            foreach (KeyValuePair<string, List<Tuple<string, Shared.Models.Property>>> tuples in filePropertiesKeyValuePairs)
            {
                valuePairs = new Dictionary<int, G_Index>();
                directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, tuples.Key, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: "Unknown C", collectionDescription: string.Empty);
                foreach (Tuple<string, Shared.Models.Property> tuple in tuples.Value)
                {
                    fileInfo = new FileInfo(Path.Combine(directoryInfoCollection[0].Replace("<>", "{}"), string.Concat(Path.GetFileNameWithoutExtension(tuple.Item1), ".json")));
                    if (!fileInfo.FullName.Contains(configuration.ResultAllInOne) && !fileInfo.Exists)
                    {
                        if (fileInfo.Directory?.Parent is null)
                            throw new Exception();
                        parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name);
                        if (File.Exists(parentCheck))
                            File.Delete(parentCheck);
                    }
                    if (_Configuration.PropertiesChangedForIndex)
                        indexInfo = null;
                    else if (!fileInfo.Exists)
                        indexInfo = null;
                    else
                        indexInfo = GetIndexInfo(fileInfo, parseExceptions);
                    if (indexInfo?.Index is not null)
                    {
                        indices.Add(indexInfo.Index.Value);
                        valuePairs.Add(indexInfo.Index.Value, indexInfo);
                    }
                    else
                        neededTuples.Add(new Tuple<List<string>, string, Shared.Models.Property>(new List<string> { tuple.Item1 }, fileInfo.FullName, tuple.Item2));
                }
                indexInfoTuples.Add(new Tuple<string, Dictionary<int, G_Index>>(tuples.Key, valuePairs));
            }
            if (_Configuration.MappedMaxIndex.HasValue)
                break;
            WriteNeeded(indices, neededTuples);
        }
        if (parseExceptions.Any())
            throw new Exception(string.Join(Environment.NewLine, parseExceptions));
        if (neededTuples.Any())
            throw new Exception();
        WriteGroup(configuration, outputResolution, indexInfoTuples);
        AppendTSV(configuration, outputResolution, filePropertiesKeyValuePairs);
    }

    string Shared.Models.Stateless.Methods.IIndex.TestStatic_GetJson(string jsonFileFullName, FileInfo fileInfo) => throw new NotImplementedException();

}