using System;
using System.Collections.Generic;
using System.Linq;
using PkmnLibSharp.Utilities;

namespace PkmnLibSharp.Library
{
    public class TypeLibrary : PointerWrapper
    {
        private readonly Dictionary<string, byte> _cache =
            new Dictionary<string, byte>(StringComparer.InvariantCultureIgnoreCase);

        internal TypeLibrary(IntPtr ptr) : base(ptr)
        {
        }

        public TypeLibrary(ulong initialCapacity) : base(
            Creaturelib.Generated.TypeLibrary.Construct(initialCapacity))
        {
        }

        public byte GetTypeId(string typeName)
        {
            if (_cache.TryGetValue(typeName, out var b))
                return b;
            Creaturelib.Generated.TypeLibrary.GetTypeId(ref b, Ptr, typeName.ToPtr()).Assert();
            _cache.Add(typeName, b);
            return b;
        }

        public byte RegisterType(string typeName)
        {
            byte b = 0;
            Creaturelib.Generated.TypeLibrary.RegisterType(ref b, Ptr, typeName.ToPtr()).Assert();
            _cache.Add(typeName, b);
            return b;
        }

        public void SetEffectiveness(byte attackingId, byte defensiveId, float effectiveness)
        {
            Creaturelib.Generated.TypeLibrary.SetEffectiveness(Ptr, attackingId, defensiveId, effectiveness);
        }

        public float GetSingleEffectiveness(byte attackingId, byte defensiveId)
        {
            float f = 0;
            Creaturelib.Generated.TypeLibrary.GetSingleEffectiveness(ref f, Ptr, attackingId, defensiveId)
                .Assert();
            return f;
        }

        public float GetEffectiveness(byte attackingId, byte[] defensiveIds)
        {
            float f = 0;
            Creaturelib.Generated.TypeLibrary.GetEffectiveness(ref f, Ptr, attackingId, defensiveIds.ArrayPtr(),
                (ulong) defensiveIds.Length).Assert();
            return f;
        }

        public string GetTypeName(byte typeId)
        {
            foreach (var kv in _cache.Where(kv => kv.Value == typeId))
            {
                return kv.Key;
            }

            var ptr = IntPtr.Zero;
            Creaturelib.Generated.TypeLibrary.GetTypeName(ref ptr, Ptr, typeId).Assert();
            var s = ptr.PtrString()!;
            _cache[s] = typeId;
            return s;
        }

        protected override void DeletePtr()
        {
            Creaturelib.Generated.TypeLibrary.Destruct(Ptr);
        }
    }
}