using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using PkmnLib.Dataloader.Models;
using PkmnLib.Static.Libraries;
using PkmnLib.Static.Species;
using PkmnLib.Static.Utils;

namespace PkmnLib.Dataloader;

public static class AbilityDataLoader
{
    private static Dictionary<string, SerializedAbility> LoadAbilitiesData(Stream stream)
    {
        var obj = JsonSerializer.Deserialize<JsonObject>(stream);
        if (obj == null)
            throw new InvalidDataException("Ability data is empty.");
        obj.Remove("$schema");
        var cleanedString = obj.ToJsonString();

        var objects = JsonSerializer.Deserialize<Dictionary<string, SerializedAbility>>(cleanedString,
            new JsonSerializerOptions()
            {
                PropertyNameCaseInsensitive = true,
            });
        if (objects == null)
            throw new InvalidDataException("Ability data is empty.");
        return objects;
    }

    public static AbilityLibrary LoadAbilities(Stream[] streams)
    {
        var library = new AbilityLibrary();
        var objects = streams.SelectMany(LoadAbilitiesData);
        if (objects == null)
            throw new InvalidDataException("Ability data is empty.");
        var abilities = objects.Select(x => DeserializeAbility(x.Key, x.Value));
        foreach (var a in abilities)
            library.Add(a);
        return library;
    }

    public static AbilityLibrary LoadAbilities(Stream stream)
    {
        var library = new AbilityLibrary();
        var objects = LoadAbilitiesData(stream);
        if (objects == null)
            throw new InvalidDataException("Ability data is empty.");
        
        var abilities = objects.Select(x => DeserializeAbility(x.Key, x.Value));
        foreach (var a in abilities)
            library.Add(a);
        return library;
    }

    private static AbilityImpl DeserializeAbility(string name, SerializedAbility serialized)
    {
        var effect = serialized.Effect;
        var parameters = serialized.Parameters.ToDictionary(x => (StringKey)x.Key, x => x.Value.ToParameter());

        StringKey? effectName = effect == null ? null! : new StringKey(effect);

        var ability = new AbilityImpl(name, effectName, parameters);
        return ability;
    }
}