using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Phares.Shared;
using ShellProgressBar;
using System.Text;
using System.Text.Json;
using View_by_Distance.Metadata.Query.Models;
using View_by_Distance.Shared.Models.Methods;

namespace View_by_Distance.Metadata.Query;

public class MetadataQuery
{

    private readonly AppSettings _AppSettings;
    private readonly string _WorkingDirectory;
    private readonly Configuration _Configuration;
    private readonly IsEnvironment _IsEnvironment;
    private readonly IConfigurationRoot _ConfigurationRoot;
    private readonly Property.Models.Configuration _PropertyConfiguration;

    public MetadataQuery(List<string> args, ILogger<Program> logger, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console)
    {
        if (isSilent)
        { }
        if (console is null)
        { }
        _AppSettings = appSettings;
        _IsEnvironment = isEnvironment;
        long ticks = DateTime.Now.Ticks;
        _WorkingDirectory = workingDirectory;
        _ConfigurationRoot = configurationRoot;
        Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
        Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration);
        _PropertyConfiguration = propertyConfiguration;
        _Configuration = configuration;
        logger?.LogInformation(propertyConfiguration.RootDirectory);
        Verify();
        MetadataQueryFilesInDirectories(logger, ticks);
    }

    private void Verify()
    {
        if (_AppSettings is null)
        { }
        if (_IsEnvironment is null)
        { }
        if (_Configuration is null)
        { }
        if (_ConfigurationRoot is null)
        { }
        if (_WorkingDirectory is null)
        { }
        if (_PropertyConfiguration is null)
        { }
    }

    private List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> GetCollection(long ticks)
    {
        int count;
        string json;
        string message;
        string fileName;
        ProgressBar progressBar;
        const string fileSearchFilter = "*";
        const bool useCeilingAverage = true;
        const string directorySearchFilter = "*";
        Dictionary<string, List<KeyValuePair<string, string>>>? dictionary;
        List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> collection = new();
        ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
        List<string[]> filesCollection = Shared.Models.Stateless.Methods.IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
        foreach (string[] files in filesCollection)
        {
            if (!files.Any())
                continue;
            message = $"{ticks}) Reading files for <{files.FirstOrDefault()}> - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
            progressBar = new(files.Length, message, options);
            foreach (string file in files)
            {
                count = 0;
                progressBar.Tick();
                json = File.ReadAllText(file);
                fileName = Path.GetFileName(file);
                dictionary = JsonSerializer.Deserialize<Dictionary<string, List<KeyValuePair<string, string>>>>(json);
                if (dictionary is null)
                    continue;
                foreach (KeyValuePair<string, List<KeyValuePair<string, string>>> keyValuePair in dictionary)
                {
                    foreach (KeyValuePair<string, string> keyValue in keyValuePair.Value)
                        count++;
                }
                foreach (KeyValuePair<string, List<KeyValuePair<string, string>>> keyValuePair in dictionary)
                {
                    foreach (KeyValuePair<string, string> keyValue in keyValuePair.Value)
                        collection.Add(new(fileName, count.ToString("000000"), keyValuePair.Key, keyValue.Key, keyValue.Value));
                }
            }
            progressBar.Dispose();
        }
        return collection;
    }

    private static Dictionary<string, List<string>> GetKeyValuePairs(List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> matches)
    {
        string key;
        string line;
        List<string>? valuePairs;
        Dictionary<string, List<string>> keyValuePairs = new();
        foreach ((string fileName, string count, string tagGroup, string tagIdName, string value) in matches)
        {
            key = $"{tagGroup}\t{tagIdName}\t{value.Trim()}";
            line = $"{tagGroup}\t{tagIdName}\t{value.Trim()}\t{count}\t{fileName}";
            if (!keyValuePairs.TryGetValue(key, out valuePairs))
            {
                keyValuePairs.Add(key, new());
                if (!keyValuePairs.TryGetValue(key, out valuePairs))
                    throw new Exception();
            }
            valuePairs.Add(line);
        }
        return keyValuePairs;
    }

    private void MetadataQueryFilesInDirectories(ILogger<Program>? logger, long ticks)
    {
        List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> collection = GetCollection(ticks);
        logger?.LogInformation($"Ready to query {collection.Count} entries?");
        IEnumerable<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> enumerable()
        {
            foreach ((string FileName, string Count, string TagGroup, string TagIdName, string Value) l in collection)
            {
                if (l.TagIdName.StartsWith("42016\t") && l.Value != "00000000000000000000000000000000")
                {
                    yield return l;
                }
            }
        }
        List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> matches = enumerable().ToList();
        if (matches.Any())
        {
            matches.Sort();
            StringBuilder stringBuilder = new();
            Dictionary<string, List<string>> keyValuePairs = GetKeyValuePairs(matches);
            foreach (KeyValuePair<string, List<string>> keyValuePair in keyValuePairs)
            {
                if (keyValuePair.Value.Count != 2)
                    continue;
                foreach (string line in keyValuePair.Value)
                    _ = stringBuilder.AppendLine(line);
            }
            string checkFile = $"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv";
            string text = stringBuilder.ToString();
            _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, text, updateToWhenMatches: null, compareBeforeWrite: true, updateDateWhenMatches: false);
        }
    }

}