using System.Collections;
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Utils;

namespace PkmnLib.Static.Libraries;

/// <summary>
/// A basic library for data types. Stores data both by name and by index.
/// </summary>
public abstract class DataLibrary<T> : IEnumerable<T> where T : INamedValue
{
    /// <summary>
    /// The underlying data storage.
    /// </summary>
    protected readonly Dictionary<StringKey, T> Data = new();

    private readonly List<T> _values = [];

    /// <summary>
    /// Adds a value to the library.
    /// </summary>
    public void Add(T value)
    {
        Data.Add(value.Name, value);
        _values.Add(value);
    }

    /// <summary>
    /// Removes a value from the library.
    /// </summary>
    public void Remove(T value)
    {
        Data.Remove(value.Name);
        _values.Remove(value);
    }

    /// <summary>
    /// Try to get a value from the library. Returns false if the value is not found.
    /// </summary>
    public bool TryGet(StringKey key, [MaybeNullWhen(false)] out T value) => Data.TryGetValue(key, out value);

    /// <summary>
    /// Get a random value from the library.
    /// </summary>
    public T GetRandom(IRandom random) => _values[random.GetInt(_values.Count)];

    /// <summary>
    /// The number of values in the library.
    /// </summary>
    public int Count => _values.Count;

    /// <summary>
    /// Whether the library is empty.
    /// </summary>
    public bool IsEmpty => _values.Count == 0;

    /// <inheritdoc />
    public IEnumerator<T> GetEnumerator() => _values.GetEnumerator();

    /// <inheritdoc />
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}