using System.Text.Json;

namespace Insight.Agent.Services
{
    public static class Configurator
    {
        public static async ValueTask<TConfig> ReadAsync<TConfig>(string file, CancellationToken cancellationToken = default)
            where TConfig : class
        {
            var json = await File.ReadAllTextAsync(file, cancellationToken);

            if (JsonSerializer.Deserialize<TConfig>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, WriteIndented = true }) is not TConfig config)
            {
                throw new InvalidDataException($"Failed to deserialize ({file})");
            }

            return config;
        }
        public static async ValueTask<JsonDocument> ReadJsonAsync(string file, CancellationToken cancellationToken = default)
        {
            var json = await File.ReadAllTextAsync(file, cancellationToken);

            if (JsonDocument.Parse(json) is not JsonDocument doc)
            {
                throw new InvalidDataException($"Failed to deserialize ({file})");
            }

            return doc;
        }
        public static async ValueTask<IDictionary<string, object>> ReadDictionaryAsync(string file, CancellationToken cancellationToken = default)
        {
            var json = await File.ReadAllTextAsync(file, cancellationToken);

            if (JsonSerializer.Deserialize<IDictionary<string, object>>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, WriteIndented = true }) is not IDictionary<string, object> config)
            {
                throw new InvalidDataException($"Failed to deserialize ({file})");
            }

            return config;
        }

        public static async ValueTask WriteAsync<TConfig>(TConfig config, string file, CancellationToken cancellationToken) where TConfig : class
        {
            await WriteToFileAsync(config, file, cancellationToken);
        }
        public static async ValueTask WriteAsync(JsonDocument config, string file, CancellationToken cancellationToken)
        {
            await WriteToFileAsync(config, file, cancellationToken);
        }
        public static async ValueTask WriteAsync(IDictionary<string, object?> config, string file, CancellationToken cancellationToken)
        {
            await WriteToFileAsync(config, file, cancellationToken);
        }

        public static async ValueTask AddOrUpdateAsync(KeyValuePair<string, object> data, string file, CancellationToken cancellationToken)
        {
            var readData = await ReadDictionaryAsync(file, cancellationToken);

            var key = readData.Keys.FirstOrDefault(dic => string.Compare(dic, data.Key, StringComparison.OrdinalIgnoreCase) == 0);

            if (key is null)
            {
                readData.Add(data.Key, data.Value);
            }
            else
            {
                readData[key] = data.Value;
            }

            await WriteToFileAsync(readData, file, cancellationToken);
        }
        public static async ValueTask RemoveAsync(string data, string file, CancellationToken cancellationToken)
        {
            var readData = await ReadDictionaryAsync(file, cancellationToken);

            var key = readData.Keys.FirstOrDefault(dic => string.Compare(dic, data, StringComparison.OrdinalIgnoreCase) == 0);

            if (key is null)
            {
                return;
            }
            else
            {
                readData.Remove(key);
            }

            await WriteToFileAsync(readData, file, cancellationToken);
        }

        private static async ValueTask WriteToFileAsync<TData>(TData data, string file, CancellationToken cancellationToken)
        {
            var json = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true });

            await File.WriteAllTextAsync(file, json, cancellationToken);
        }
    }
}