namespace Hims.Shared.Dapper.Extensions
{
    using System;
    using System.Collections.Concurrent;
    using System.Linq;
    using System.Reflection;

    /// <summary>
    /// The type extensions.
    /// </summary>
    public static class TypeExtensions
    {
        /// <summary>
        /// The _reflection property cache.
        /// </summary>
        private static readonly ConcurrentDictionary<Type, PropertyInfo[]> ReflectionPropertyCache = new ConcurrentDictionary<Type, PropertyInfo[]>();

        /// <summary>
        /// The find class properties.
        /// </summary>
        /// <param name="objectType">
        /// The object type.
        /// </param>
        /// <returns>
        /// The <see cref="PropertyInfo"/>.
        /// </returns>
        public static PropertyInfo[] FindClassProperties(this Type objectType)
        {
            if (ReflectionPropertyCache.ContainsKey(objectType))
            {
                return ReflectionPropertyCache[objectType];
            }

            var result = objectType.GetProperties().ToArray();

            ReflectionPropertyCache.TryAdd(objectType, result);

            return result;
        }

        /// <summary>
        /// The is generic type.
        /// </summary>
        /// <param name="type">
        /// The type.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool IsGenericType(this Type type) => type.IsGenericType;

        /// <summary>
        /// The is enum.
        /// </summary>
        /// <param name="type">
        /// The type.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool IsEnum(this Type type) => type.IsEnum;

        /// <summary>
        /// The is value type.
        /// </summary>
        /// <param name="type">
        /// The type.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool IsValueType(this Type type) => type.IsValueType;

        /// <summary>
        /// The is bool.
        /// </summary>
        /// <param name="type">
        /// The type.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool IsBool(this Type type) => type == typeof(bool);
    }
}