using MadRunFabric.Common.DbContext;
using MadRunFabric.Common.Options;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MadRunFabric.Common
{
    public abstract class BaseRepository<T, TKey> : IRepository<T, TKey> where T : class, IBaseModel<TKey>
    {
        private readonly ILogger<BaseRepository<T, TKey>> _logger;
        protected BaseContext _context;
        protected readonly IMongoCollection<T> _collection;

        public BaseRepository(IOptions<MongodbOptions> settings, ILogger<BaseRepository<T, TKey>> logger)
        {
            _logger = logger;
            _context = new BaseContext(settings);
            _collection = _context.GetCollection<T>();//获取集合
        }


        /// <summary>
        /// 异步添加一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<bool> Add(T entity)
        {
            try
            {
                await _collection.InsertOneAsync(entity);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 异步添加多条数据
        /// </summary>
        /// <param name="entitys"></param>
        /// <returns></returns>
        public async Task<bool> AddRange(List<T> entitys)
        {
            try
            {
                await _collection.InsertManyAsync(entitys);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return false;
            }

        }

        /// <summary>
        /// 获取数量
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<long> Count(Expression<Func<T, bool>> @where = null)
        {
            try
            {

                return await _collection.CountAsync(@where);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }



        public void Dispose()
        {
            throw new NotImplementedException();
        }


        /// <summary>
        /// 依据条件查询数据
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<IEnumerable<T>> Get(Expression<Func<T, bool>> @where = null)
        {
            try
            {
                var task = await _collection.FindAsync(@where);
                return task.ToList();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }

        /// <summary>
        /// 依据查询条件查询所有数据 包含显示字段 排序
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="field"></param>
        /// <param name="sort"></param>
        /// <returns></returns>
        public async Task<IEnumerable<T>> Get(FilterDefinition<T> filter, string[] field = null, SortDefinition<T> sort = null)
        {
            try
            {
                //不指定查询字段
                if (field == null || field.Length == 0)
                {
                    if (filter == null)
                    {
                        if (sort == null) return await _collection.Find(_ => true).ToListAsync();
                        //进行排序
                        return await _collection.Find(_ => true).Sort(sort).ToListAsync();
                    }

                    if (sort == null) return await _collection.Find(filter).ToListAsync();
                    //进行排序
                    return await _collection.Find(filter).Sort(sort).ToListAsync();
                }

                #region 指定查询字段
                //指定查询字段
                var fieldList = new List<ProjectionDefinition<T>>();

                for (int i = 0; i < field.Length; i++)
                {
                    fieldList.Add(Builders<T>.Projection.Include(field[i].ToString()));
                }
                var projection = Builders<T>.Projection.Combine(fieldList);
                fieldList?.Clear();

                if (sort == null) return await _collection.Find(filter).Project<T>(projection).ToListAsync();
                //排序查询
                return await _collection.Find(filter).Sort(sort).Project<T>(projection).ToListAsync();
                #endregion

            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }

        
        /// <summary>
        /// 查询所有数据
        /// </summary>
        /// <returns></returns>
        public async Task<IEnumerable<T>> GetAll()
        {
            try
            {
                return await _collection.Find(_ => true).ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }

        /// <summary>
        ///  分页查询数据列表
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="sort"></param>
        /// <returns></returns>
        public async Task<IEnumerable<T>> GetByPage(FilterDefinition<T> filter, int pageIndex, int pageSize, SortDefinition<T> sort = null)
        {
            try
            {
                //没有查询条件
                if (filter == null)
                {
                    if (sort == null)
                        return await _collection.Find(_ => true).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
                    //排序
                    return await _collection.Find(_ => true).Sort(sort).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
                }

                if (sort == null) return await _collection.Find(filter).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
                //排序
                return await _collection.Find(filter).Sort(sort).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();

            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }

        /// <summary>
        /// 查询一条数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> GetSingle(TKey key)
        {
            var filter = Builders<T>.Filter.Eq("id", key);

            try
            {
                return await _collection.Find(filter).FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }

        /// <summary>
        /// 根据查询条件查出
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<T> GetSingle(Expression<Func<T, bool>> @where = null)
        {
            try
            {
                return await _collection.Find(@where).FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }

        /// <summary>
        /// 查询一条数据 条件 排序
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<T> GetSingle(Expression<Func<T, bool>> @where = null, SortDefinition<T> sort = null)
        {
            try
            {
                if (sort == null)
                    return await _collection.Find(@where).FirstOrDefaultAsync();
                return await _collection.Find(@where).Sort(sort).FirstOrDefaultAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }

        /// <summary>
        /// 删除一项 根据id
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<bool> Remove(TKey key)
        {
            try
            {
                DeleteResult actionResult = await _collection.DeleteOneAsync(Builders<T>.Filter.Eq("id", key));

                return actionResult.IsAcknowledged && actionResult.DeletedCount > 0;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }



        /// <summary>
        /// 依据条件删除多项
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<bool> Remove(Expression<Func<T, bool>> @where = null)
        {
            try
            {
                DeleteResult actionResult = await _collection.DeleteManyAsync(@where);

                return actionResult.IsAcknowledged && actionResult.DeletedCount > 0;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                throw ex;
            }
        }


        /// <summary>
        /// 删除所有数据
        /// </summary>
        /// <returns></returns>
        public async Task<bool> RemoveAll()
        {
            try
            {
                DeleteResult actionResult = await _collection.DeleteManyAsync(new BsonDocument());

                return actionResult.IsAcknowledged
                    && actionResult.DeletedCount > 0;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 修改数据
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<bool> Update(T entity)
        {
            try
            {
                //修改条件
                FilterDefinition<T> filter = Builders<T>.Filter.Eq("id", entity.id);
                //要修改的字段
                var list = new List<UpdateDefinition<T>>();
                foreach (var item in entity.GetType().GetProperties())
                {
                    if (item.Name.ToLower() == "id") continue;
                    list.Add(Builders<T>.Update.Set(item.Name, item.GetValue(entity)));
                }
                var updatefilter = Builders<T>.Update.Combine(list);
                var r = await _collection.UpdateOneAsync(filter, updatefilter, null);
                //return r.IsAcknowledged && r.ModifiedCount > 0;
                return r.IsAcknowledged ;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return false;
            }
        }
        public async Task<bool> Update(string id, Dictionary<object, object> dic)
        {
            try
            {
                //修改条件
                FilterDefinition<T> filter = Builders<T>.Filter.Eq("_id", new ObjectId(id));
                //要修改的字段
                var list = new List<UpdateDefinition<T>>();
                foreach (var item in dic)
                {
                    list.Add(Builders<T>.Update.Set(item.Key.ToString(), item.Value));
                }
                var updatefilter = Builders<T>.Update.Combine(list);
                var r = await _collection.UpdateOneAsync(filter, updatefilter, null);
                //return r.IsAcknowledged && r.ModifiedCount > 0;
                return r.IsAcknowledged;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return false;
            }
        }
        public async Task<bool> UpdateOne(T entity)
        {
            try
            {
                //修改条件
                FilterDefinition<T> filter = Builders<T>.Filter.Eq("id", entity.id);
                var query = await _collection.Find(filter).FirstOrDefaultAsync();
                //要修改的字段
                var list = new List<UpdateDefinition<T>>();
                //要删除的字段
                var dellist = new List<UpdateDefinition<T>>();
                foreach (var property in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    //非空的复杂类型
                    if (property.PropertyType.IsClass && property.PropertyType != typeof(string) && property.GetValue(entity) != null)
                    {
                        var subarray = property.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public);

                        if (typeof(IList).IsAssignableFrom(property.PropertyType))
                        {
                            #region 集合类型
                            foreach (var sub in subarray)
                            {
                                //if (sub.PropertyType.IsClass && sub.PropertyType != typeof(string))
                                if (sub.PropertyType.IsClass)
                                {
                                    //var arr = property.GetValue(entity) as IList;
                                    //var arrold = property.GetValue(query) as IList;
                                    var enumobj = property.GetValue(entity) as IEnumerable<object>;
                                    //var enumoldobj = property.GetValue(query) as IEnumerable<object>;

                                    dellist.Add(Builders<T>.Update.Unset(property.Name));
                                    list.Add(Builders<T>.Update.PushEach(property.Name, enumobj));

                                    //if (sub.PropertyType != typeof(string))
                                    //{
                                    //    var subinnerarray = sub.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
                                    //    if (arr != null && arr.Count > 0)
                                    //    {

                                    //        for (int s = 0; s < arr.Count; s++)
                                    //        {

                                    //            foreach (var subInner in subinnerarray)
                                    //            {
                                    //                //propertyName.index.innerPropertyName
                                    //                list.Add(Builders<T>.Update.Set(property.Name + "." + s + "." + subInner.Name, subInner.GetValue(arr[s])));
                                    //            }
                                    //        }
                                    //    }

                                    //    int n = 0;
                                    //    if (arr != null) { n = arr.Count; }
                                    //    int o = 0;
                                    //    if (arrold != null) { o = arrold.Count; }
                                    //    if (o > n)
                                    //    {
                                    //        for (int i = n; i < arrold.Count; i++)
                                    //        {
                                    //            switch (sub.PropertyType.Name)
                                    //            {
                                    //                case "ExtensionModel":
                                    //                    FilterDefinition<ExtensionModel> subfilterexten = Builders<ExtensionModel>.Filter.Eq(subinnerarray[0].Name, subinnerarray[0].GetValue(arrold[i]));
                                    //                    dellist.Add(Builders<T>.Update.PullFilter(property.Name, subfilterexten));
                                    //                    break;
                                    //                case "FileBaseModel":
                                    //                    FilterDefinition<FileBaseModel> subfilterfile = Builders<FileBaseModel>.Filter.Eq(subinnerarray[0].Name, subinnerarray[0].GetValue(arrold[i]));
                                    //                    dellist.Add(Builders<T>.Update.PullFilter(property.Name, subfilterfile));
                                    //                    break;
                                    //                case "MaterialModel":
                                    //                    FilterDefinition<MaterialModel> subfiltermater = Builders<MaterialModel>.Filter.Eq(subinnerarray[0].Name, subinnerarray[0].GetValue(arrold[i]));
                                    //                    dellist.Add(Builders<T>.Update.PullFilter(property.Name, subfiltermater));
                                    //                    break;
                                    //            }
                                    //        }
                                    //    }

                                    //}
                                    //else
                                    //{
                                    //    dellist.Add(Builders<T>.Update.PullAll(property.Name, enumoldobj));
                                    //    list.Add(Builders<T>.Update.PushEach(property.Name, enumobj));
                                    //}
                                }
                            }
                            #endregion
                        }
                        else
                        {
                            #region 实体类型
                            //复杂类型，导航属性，类对象和集合对象 
                            foreach (var sub in subarray)
                            {
                                list.Add(Builders<T>.Update.Set(property.Name + "." + sub.Name, sub.GetValue(property.GetValue(entity))));
                            }
                            #endregion
                        }
                    }
                    else
                    {
                        if (property.Name.ToLower() != "id")//更新集中不能有实体键_id
                        {
                            list.Add(Builders<T>.Update.Set(property.Name, property.GetValue(entity)));
                        }
                    }
                }

                if (dellist.Count > 0)
                {
                    var delfilter = Builders<T>.Update.Combine(dellist);
                    var d = await _collection.UpdateOneAsync(filter, delfilter, null);
                }

                var updatefilter = Builders<T>.Update.Combine(list);
                var r = await _collection.UpdateOneAsync(filter, updatefilter, null);

                //return r.IsAcknowledged && r.ModifiedCount > 0;

                return r.IsAcknowledged;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 批量修改数据
        /// </summary>
        public async Task<bool> UpdateManay(T entity, Dictionary<string, string> dic, FilterDefinition<T> filter = null)
        {
            try
            {
                //要修改的字段
                var list = new List<UpdateDefinition<T>>();
                foreach (var item in entity.GetType().GetProperties())
                {
                    if (!dic.ContainsKey(item.Name)) continue;
                    var value = dic[item.Name];
                    list.Add(Builders<T>.Update.Set(item.Name, value));
                }
                var updatefilter = Builders<T>.Update.Combine(list);
                var r = await _collection.UpdateManyAsync(filter, updatefilter);
                return r.IsAcknowledged && r.ModifiedCount > 0;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 异步根据条件获取总数
        /// </summary>
        /// <param name="filter">条件</param>
        /// <returns></returns>
        public async Task<long> CountAsync(FilterDefinition<T> filter = null)
        {
            try
            {
                return await _collection.CountAsync(filter == null ? FilterDefinition<T>.Empty : filter);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return 0;
            }
        }

        /// <summary>
        /// 异步添加一条数据并返回ID
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<string> AddRetID(T entity)
        {
            try
            {
                await _collection.InsertOneAsync(entity);
                return entity.id.ToString();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
                return null;
            }
        }

   
    }
}
