using System.Reflection;
using PkmnLib.Static.Libraries;

namespace PkmnLib.Dynamic.Plugins;

/// <summary>
/// Interface for plugins that provide resources.
/// </summary>
public interface IResourceProvider
{
    /// <summary>
    /// The settings for the library. This is used to configure the library and its resources.
    /// </summary>
    LibrarySettings? Settings { get; }

    /// <summary>
    /// Gets the resource for the given type. This is used to load resources from the plugin. Returns null if the
    /// plugin does not provide the resource.
    /// </summary>
    IResourceResult? GetResource(ResourceFileType request);
}

/// <summary>
/// Enum for the different types of resources that can be loaded.
/// </summary>
public enum ResourceFileType
{
    /// <summary>
    /// Unknown type. This is used for errors and should not be used in normal code.
    /// </summary>
    Unknown,

    /// <summary>
    /// The type for the types of Pokémon. This includes the type effectiveness chart and the type names.
    /// </summary>
    Types,

    /// <summary>
    /// The type for the natures of Pokémon. This includes the nature names and the nature effects.
    /// </summary>
    Natures,

    /// <summary>
    /// The type for the moves of Pokémon. This includes the move names and the move effects.
    /// </summary>
    Moves,

    /// <summary>
    /// The type for the items of Pokémon. This includes the item names and the item effects.
    /// </summary>
    Items,

    /// <summary>
    /// The type for the abilities of Pokémon. This includes the ability names and the ability effects.
    /// </summary>
    Abilities,

    /// <summary>
    /// The type for the growth rates of Pokémon. This includes the growth rate names and the growth rate effects.
    /// </summary>
    GrowthRates,

    /// <summary>
    /// The type for the species of Pokémon. This includes the species names and the species effects.
    /// </summary>
    Species,
}

/// <summary>
/// Interface for a resource result. This is used to load resources from the plugin.
/// </summary>
public interface IResourceResult
{
    /// <summary>
    /// Opens the resource and returns a stream. This is used to load the resource from the plugin.
    /// </summary>
    Stream Open();
}

/// <summary>
/// Class for a resource result that is loaded from an embedded resource in an assembly.
/// </summary>
public class AssemblyResourceResult : IResourceResult
{
    private readonly string _resourceName;
    private readonly Assembly _assembly;

    /// <inheritdoc cref="AssemblyResourceResult" />
    public AssemblyResourceResult(string resourceName, Assembly assembly)
    {
        _resourceName = resourceName;
        _assembly = assembly;
    }

    /// <inheritdoc />
    public Stream Open() => _assembly.GetManifestResourceStream(_resourceName) ??
                            throw new InvalidOperationException(
                                $"Resource '{_resourceName}' not found in assembly '{_assembly.FullName}'.");
}