using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using static Sieve.Extensions.MethodInfoExtended;

namespace MEU.API.Utils
{

    public class ReflectionHelper
    {
        private static Random random = new Random();
        public static string RandomString(int length)
        {
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            return new string(Enumerable.Repeat(chars, length)
              .Select(s => s[random.Next(s.Length)]).ToArray());
        }

        public static object AddPropertyToObject(object oModel, string NewPropertyName, object NewPropertyValue)
        {
            if (oModel == null)
            {
                return null;
            }
            Dictionary<string, object> sData = new Dictionary<string, object>();
            object oReturn = new object();
            foreach (var prop in oModel.GetType().GetProperties())
            {
                if (!prop.GetGetMethod().IsVirtual)
                {
                    sData.Add(prop.Name, prop.GetValue(oModel, null));
                }
            }

            sData.Add(NewPropertyName, NewPropertyValue);
            return sData;

        }

        public static object AddPropertiesToObject(object oModel, Dictionary<string, object> PropertyList)
        {
            if (oModel == null)
            {
                return null;
            }
            Dictionary<string, object> sData = new Dictionary<string, object>();
            object oReturn = new object();
            foreach (var prop in oModel.GetType().GetProperties())
            {
                if (!prop.GetGetMethod().IsVirtual)
                {
                    sData.Add(prop.Name, prop.GetValue(oModel, null));
                }
            }

            foreach (KeyValuePair<string, object> item in PropertyList)
            {
                sData.Add(item.Key, item.Value);
            }
            return sData;

        }
        public static object ModelToObject(object oModel)
        {
            if (oModel == null)
            {
                return null;
            }
            Dictionary<string, object> sData = new Dictionary<string, object>();
            object oReturn = new object();
            foreach (var prop in oModel.GetType().GetProperties())
            {
                if (!prop.GetGetMethod().IsVirtual)
                {
                    sData.Add(prop.Name, prop.GetValue(oModel, null));
                }
            }
            return sData;
        }



        public static object ModelToObject(object oModel, string[] PropertyName)
        {
            if (oModel == null)
            {
                return null;
            }
            Dictionary<string, object> sData = new Dictionary<string, object>();
            object oReturn = new object();
            foreach (var prop in oModel.GetType().GetProperties())
            {
                if (!prop.GetGetMethod().IsVirtual)
                {
                    if (PropertyName.Where(s => s == prop.Name).Count() > 0)
                    {
                        sData.Add(prop.Name, prop.GetValue(oModel, null));
                    }
                }
            }
            return sData;
        }

        public static object ModelToObjectExcludeProperties(object oModel, string[] PropertyName)
        {
            if (oModel == null)
            {
                return null;
            }
            Dictionary<string, object> sData = new Dictionary<string, object>();
            object oReturn = new object();
            foreach (var prop in oModel.GetType().GetProperties())
            {
                if (!prop.GetGetMethod().IsVirtual)
                {
                    if (PropertyName.Where(s => s == prop.Name).Count() == 0)
                    {
                        sData.Add(prop.Name, prop.GetValue(oModel, null));
                    }
                }
            }
            return sData;
        }

        public static ExpandoObject ModelToExpandoObject(object oModel)
        {
            if (oModel == null)
            {
                return null;
            }
            ExpandoObject oReturn = new ExpandoObject();
            IDictionary<string, object> sData = (IDictionary<string, object>)oReturn;
            var dictionary = (IDictionary<string, object>)oReturn;
            foreach (var prop in oModel.GetType().GetProperties())
            {
                if (!prop.GetGetMethod().IsVirtual)
                {
                    sData.Add(prop.Name, prop.GetValue(oModel, null));
                }
            }
            return sData as ExpandoObject;
        }

        public static object ExpandoObjectToObject(IDictionary<String, Object> oModel)
        {
            if (oModel == null)
            {
                return null;
            }
            Dictionary<string, object> sData = new Dictionary<string, object>();
            foreach (var item in oModel)
            {
                sData.Add(item.Key, item.Value);
            }
            return sData;
        }

        public static object[] ArrayModelToArrObject(object[] oModel)
        {
            if (oModel == null)
            {
                return null;
            }
            List<object> objectlst = new List<object>();
            foreach (var item in oModel)
            {
                objectlst.Add(ModelToObject(item));
            }
            return objectlst.ToArray();
        }

        public static object[] ArrayModelToArrObject(object[] oModel, string[] lstPropertyName)
        {
            if (oModel == null)
            {
                return null;
            }
            List<object> objectlst = new List<object>();
            foreach (var item in oModel)
            {
                objectlst.Add(ModelToObject(item, lstPropertyName));
            }
            return objectlst.ToArray();
        }

        public static List<Object> ListModelToLstObject<T>(List<T> oModel)
        {
            if (oModel == null)
            {
                return null;
            }

            List<Object> objectlst = new List<Object>();

            foreach (Object item in oModel)
            {
                objectlst.Add(ModelToObject(item));
            }

            return objectlst;

        }
        public static T ObjectToModel<T>(object InputObject) where T : class
        {
            var result = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(InputObject), typeof(T));
            return (T)result;
        }

        public static List<T> ListObjectToListModel<T>(List<object> InputObject) where T : class
        {
            List<T> modellst = new List<T>();

            foreach (Object item in InputObject)
            {
                modellst.Add(ObjectToModel<T>(item));
            }
            return modellst;
        }


        public static Object CloneObj(Object oldObj, Object newObj, String[] exluceList)
        {
            try
            {
                newObj = JsonConvert.DeserializeObject<Dictionary<string, object>>(newObj.ToString());
                var returnObj = new Dictionary<string, Object>();
                foreach (KeyValuePair<string, object> prop in (Dictionary<string, object>)oldObj)
                {
                    //Check new object has property of old object
                    returnObj.Add(prop.Key.ToString(), prop.Value);
                    Dictionary<string, Object> find = new Dictionary<string, object>();
                    foreach (KeyValuePair<string, object> propOfNewObj in (Dictionary<string, object>)newObj)
                    {

                        if (propOfNewObj.Key.ToString() == prop.Key.ToString())
                        {
                            find.Add(propOfNewObj.Key.ToString(), propOfNewObj.Value);
                        }
                    }
                    if (find.Count > 0 && !exluceList.Contains(prop.Key.ToString()))
                    {
                        returnObj[prop.Key.ToString()] = find[prop.Key.ToString()];

                    }
                }
                return returnObj as Object;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        public static dynamic Cast(dynamic obj, Type castTo)
        {
            try
            {
                return Convert.ChangeType(obj, castTo);
            }
            catch (Exception)
            {

                return null;
            }
        }



        protected static object ChangeType(object value, Type conversion)
        {
            var t = conversion;

            if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null)
                {
                    return null;
                }

                t = Nullable.GetUnderlyingType(t);
            }
            if (conversion.BaseType.Name.Equals("Array"))
            {
                string[] arr = ((IEnumerable)value).Cast<object>()
                             .Select(x => x.ToString())
                             .ToArray();
                return arr;
                //string data = value.ToString().Trim();
                //if (data.Length>2)
                //{
                //    data = data.Substring(1, data.Length - 2);
                //    var ta = data.ToString().Split(',').Select(s => Convert.ChangeType(s, conversion.GetElementType())).ToArray();
                //    Array destinationArray = Array.CreateInstance(conversion.GetElementType(), ta.Count());
                //    Array.Copy(ta, destinationArray, ta.Count());
                //    return destinationArray;
                //}

            }
            if (conversion.AssemblyQualifiedName.Contains("System.Guid"))
            {
                return Guid.Parse(value.ToString());

            }

            return Convert.ChangeType(value, t);
        }

        public static T GetObject<T>(Dictionary<string, object> dict)
        {
            KeyValuePair<string, object> dt;
            try
            {
                Type type = typeof(T);
                var obj = Activator.CreateInstance(type);

                if (dict != null)
                {
                    foreach (var kv in dict)
                    {
                        dt = kv;
                        if (kv.Value != null)// && kv.Value.GetType() == typeof(long)
                        {
                            PropertyInfo propertyInfo = type.GetProperty(kv.Key);

                            object value;
                            if (propertyInfo.PropertyType.FullName.Contains("Guid") && kv.Value.ToString().Trim() == "")
                            {
                                 value = ChangeType(null, propertyInfo.PropertyType);
                            }
                            else
                            {
                                 value = ChangeType(kv.Value, propertyInfo.PropertyType);
                            }
                            type.GetProperty(kv.Key).SetValue(obj, value, null);

                        }
                        else if (Nullable.GetUnderlyingType(obj.GetType().GetProperty(kv.Key).PropertyType) == null)
                        {
                            var value = Convert.ChangeType(kv.Value, obj.GetType().GetProperty(kv.Key).PropertyType);
                            obj.GetType().GetProperty(kv.Key).SetValue(obj, value);
                        }
                        else
                        {
                            obj.GetType().GetProperty(kv.Key).SetValue(obj, kv.Value);
                        }

                    }
                }

                return (T)obj;
            }
            catch (Exception ex)
            {
                var x = ex;
                Logs.LoggerFactory.ErrorLog(ex.ToString(), "Exception");
                throw;
            }
        }

        public static Boolean isImage(IFormFile image)
        {
            //-------------------------------------------
            //  Check the image mime types
            //-------------------------------------------
            if (image.ContentType.ToLower() != "image/jpg" &&
                        image.ContentType.ToLower() != "image/jpeg" &&
                        image.ContentType.ToLower() != "image/pjpeg" &&
                        image.ContentType.ToLower() != "image/gif" &&
                        image.ContentType.ToLower() != "image/x-png" &&
                        image.ContentType.ToLower() != "image/png")
            {
                return false;
            }

            //-------------------------------------------
            //  Check the image extension
            //-------------------------------------------
            if (Path.GetExtension(image.FileName).ToLower() != ".jpg"
                && Path.GetExtension(image.FileName).ToLower() != ".png"
                && Path.GetExtension(image.FileName).ToLower() != ".gif"
                && Path.GetExtension(image.FileName).ToLower() != ".jpeg")
            {
                return false;
            }
            return true;

        }
    }

}
