using PkmnLib.Dynamic.AI.Explicit;
using PkmnLib.Dynamic.Plugins;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Static.Libraries;

namespace PkmnLib.Dynamic.Libraries;

/// <summary>
/// The dynamic library stores a static data library, as well as holding different libraries and
/// calculators that might be customized between different generations and implementations.
/// </summary>
public interface IDynamicLibrary
{
    /// <summary>
    /// The static data is the immutable storage data for this library.
    /// </summary>
    IStaticLibrary StaticLibrary { get; }

    /// <summary>
    /// The stat calculator deals with the calculation of flat and boosted stats, based on the
    /// Pokémon's attributes.
    /// </summary>
    IBattleStatCalculator StatCalculator { get; }

    /// <summary>
    /// The damage calculator deals with the calculation of things relating to damage.
    /// </summary>
    IDamageCalculator DamageCalculator { get; }

    /// <summary>
    /// The Misc Library holds minor functions that do not fall in any of the other libraries and
    /// calculators.
    /// </summary>
    IMiscLibrary MiscLibrary { get; }

    /// <summary>
    /// The capture library deals with the calculation of the capture rate of a Pokémon.
    /// </summary>
    ICaptureLibrary CaptureLibrary { get; }

    /// <summary>
    /// The experience gain calculator deals with the calculation of experience gained by a
    /// Pokémon after defeating another Pokémon.
    /// </summary>
    IExperienceGainCalculator ExperienceGainCalculator { get; }

    /// <summary>
    /// A holder of the script types that can be resolved by this library.
    /// </summary>
    ScriptResolver ScriptResolver { get; }

    /// <summary>
    /// The deterministic AI handlers provide a way to access the various handlers used by the
    /// <see cref="ExplicitAI"/> to make decisions.
    /// </summary>
    IReadOnlyExplicitAIHandlers ExplicitAIHandlers { get; }

    /// <summary>
    /// Library for handling of whether a Pokemon can evolve.
    /// </summary>
    IEvolutionLibrary EvolutionLibrary { get; }
}

/// <inheritdoc />
public class DynamicLibraryImpl : IDynamicLibrary
{
    /// <summary>
    /// Initializes a new instance of the <see cref="DynamicLibraryImpl"/> class, with the given
    /// plugins and static library.
    /// </summary>
    public static IDynamicLibrary Create(IEnumerable<IPlugin> plugins)
    {
        var load = LibraryLoader.LoadPlugins(plugins);

        return new DynamicLibraryImpl(load.StaticLibrary, load.Registry.BattleStatCalculator!,
            load.Registry.DamageCalculator!, load.Registry.MiscLibrary!, load.Registry.CaptureLibrary!, load.Resolver,
            load.Registry.ExplicitAIHandlers, load.Registry.ExperienceGainCalculator!);
    }

    private DynamicLibraryImpl(IStaticLibrary staticLibrary, IBattleStatCalculator statCalculator,
        IDamageCalculator damageCalculator, IMiscLibrary miscLibrary, ICaptureLibrary captureLibrary,
        ScriptResolver scriptResolver, IReadOnlyExplicitAIHandlers explicitAIHandlers,
        IExperienceGainCalculator experienceGainCalculator)
    {
        StaticLibrary = staticLibrary;
        StatCalculator = statCalculator;
        DamageCalculator = damageCalculator;
        MiscLibrary = miscLibrary;
        ScriptResolver = scriptResolver;
        ExplicitAIHandlers = explicitAIHandlers;
        ExperienceGainCalculator = experienceGainCalculator;
        CaptureLibrary = captureLibrary;
        EvolutionLibrary = new EvolutionLibrary(miscLibrary, staticLibrary.Species);
    }

    /// <inheritdoc />
    public IStaticLibrary StaticLibrary { get; }

    /// <inheritdoc />
    public IBattleStatCalculator StatCalculator { get; }

    /// <inheritdoc />
    public IDamageCalculator DamageCalculator { get; }

    /// <inheritdoc />
    public IMiscLibrary MiscLibrary { get; }

    /// <inheritdoc />
    public ICaptureLibrary CaptureLibrary { get; }

    /// <inheritdoc />
    public IExperienceGainCalculator ExperienceGainCalculator { get; }

    /// <inheritdoc />
    public ScriptResolver ScriptResolver { get; }

    /// <inheritdoc />
    public IReadOnlyExplicitAIHandlers ExplicitAIHandlers { get; }

    /// <inheritdoc />
    public IEvolutionLibrary EvolutionLibrary { get; }
}