using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace VCommon.Reflection
{
    public abstract class EnumBind<T, TBase>
    {
        public static IReadOnlyDictionary<T, Type> BindedTypes { get; }
        public static IReadOnlyDictionary<Type, T> InvertMap { get; }

        private static readonly HashSet<T> Fields;

        public static bool Contains(T value) => Fields.Contains(value);

        static EnumBind()
        {
            if (false == typeof(T).IsEnum) throw new VCommonException("Generic type argument must be Enum.");

            BindedTypes = typeof(T).GetFields().Where(p => p.FieldType == typeof(T))
                .ToDictionary(
                    k => (T)k.GetRawConstantValue(),
                    p => p.GetCustomAttributes(typeof(EnumBindAttribute))
                        .OfType<EnumBindAttribute>()
                        .Select(t => t.BindType)
                        .Single(t => typeof(TBase).IsAssignableFrom(t))
                );

            InvertMap = BindedTypes.ToDictionary(p => p.Value, p => p.Key);

            Fields = new HashSet<T>(BindedTypes.Keys);
        }
    }
}