using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using System.Linq.Dynamic.Core;
using System.Collections.Generic;
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace IRaCIS.Core.Infrastructure.Extention
{
    public static class QueryablePageListExtensions
    {


        /// <summary>
        /// 后端默认指定多字段排序（前段排序字段为空的时候），否则就是单字段排序，以前端传递的排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="pageInput">前段传递的参数</param>
        /// <param name="sortArray">后端默认指定的多字段排序，如果前端为空，就用后端默认指定的，否则以前端为准</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task<PageOutput<T>> ToPagedListAsync<T>(this IQueryable<T> source, PageInput pageInput, string[] sortArray = default, CancellationToken cancellationToken = default)
        {
            var isMultiSortFiled = false;

            if (string.IsNullOrWhiteSpace(pageInput.SortField) && sortArray != default && sortArray != null)
            {
                isMultiSortFiled = true;
            }

            if (pageInput.PageIndex <= 0)
            {
                pageInput.PageIndex = 1;
            }
            if (pageInput.PageSize <= 0)
            {
                pageInput.PageSize = 10;
            }

            var count = await source.CountAsync(cancellationToken).ConfigureAwait(false);

            if (count == 0)
            {
                return new PageOutput<T>() { CurrentPageData = new T[0] };
            }

            if (isMultiSortFiled)
            {
                var sortString = string.Join(',', sortArray);

                source = source.OrderBy(sortString);
            }
            else
            {
                #region 单字段排序，前端不传递，后端给排序字段
                //var propName = string.Empty;

                //if (string.IsNullOrWhiteSpace(pageInput.SortField))
                //{
                //    //没有指定，优先以Id排序，否则从属性里面随便取出来一个排序
                //    var propertyNameList = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(t => t.CanWrite).Select(t => t.Name).OrderBy(t => t).ToList();

                //    if (propertyNameList.Count == 0)
                //    {
                //        throw new InvalidOperationException("no default sort field.");
                //    }
                //    else
                //    {
                //        propName = propertyNameList.Contains("Id") ? "Id" : propertyNameList.FirstOrDefault();
                //    }

                //}
                //else
                //{
                //    //有值，以前段传输的为主
                //    propName = pageInput.SortField;
                //}

                //source = pageInput.Asc ? source.OrderBy(propName) : source.OrderBy(propName + " desc");
                #endregion

                source = string.IsNullOrWhiteSpace(pageInput.SortField) ? source : (pageInput.Asc ? source.OrderBy(pageInput.SortField) : source.OrderBy(pageInput.SortField + " desc"));
            }

            source = source.Skip((pageInput.PageIndex - 1) * pageInput.PageSize);
            var items = await source
                                    .Take(pageInput.PageSize)
                                    .ToArrayAsync(cancellationToken)
                                    .ConfigureAwait(false);

            var pagedList = new PageOutput<T>()
            {
                PageIndex = pageInput.PageIndex,
                PageSize = pageInput.PageSize,
                TotalCount = count,
                CurrentPageData = items
            };

            return pagedList;
        }



        /// <summary>
        ///  兼容之前后端给了默认值的，不影响之前的逻辑，只是改写法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="pageInput">  前段传递的参数</param>
        /// <param name="sortField">后端默认指定的排序字段，如果前端为空，就用后端默认指定的，否则以前端为准 </param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task<PageOutput<T>> ToPagedListAsync<T>(this IQueryable<T> source, PageInput pageInput, string sortField , CancellationToken cancellationToken = default)
        {


            if (pageInput.PageIndex <= 0)
            {
                pageInput.PageIndex = 1;
            }
            if (pageInput.PageSize <= 0)
            {
                pageInput.PageSize = 10;
            }

            var count = await source.CountAsync(cancellationToken).ConfigureAwait(false);

            if (count == 0)
            {
                return new PageOutput<T>() { CurrentPageData = new T[0] };
            }

            var propName = string.Empty;

            //前端传递 以前端为准
            if (string.IsNullOrWhiteSpace(pageInput.SortField))
            {
                propName = sortField;
            }
            else
            {
                propName= pageInput.SortField;
            }

            source = string.IsNullOrWhiteSpace(propName) ? source : (pageInput.Asc ? source.OrderBy(propName) : source.OrderBy(propName + " desc"));

            source = source.Skip((pageInput.PageIndex - 1) * pageInput.PageSize);
            var items = await source
                                    .Take(pageInput.PageSize)
                                    .ToArrayAsync(cancellationToken)
                                    .ConfigureAwait(false);

            var pagedList = new PageOutput<T>()
            {
                PageIndex = pageInput.PageIndex,
                PageSize = pageInput.PageSize,
                TotalCount = count,
                CurrentPageData = items
            };

            return pagedList;
        }


        public static async Task<List<T>> SortToListAsync<T>(this IQueryable<T> source, SortInput sortInput, string sortField="", CancellationToken cancellationToken = default)
        {
            var propName = string.Empty;

            if (string.IsNullOrWhiteSpace(sortInput.SortField))
            {
                propName = sortField;
            }
            else
            {
                propName = sortInput.SortField;
            }

            source = string.IsNullOrWhiteSpace(propName) ? source : (sortInput.Asc ? source.OrderBy(propName) : source.OrderBy(propName + " desc"));

            return await source.ToListAsync(cancellationToken);

        }

        public static async Task<List<T>> SortToListAsync<T>(this IQueryable<T> source,  string[] sortArray = default, CancellationToken cancellationToken = default)
        {
            var sortString = string.Join(',', sortArray);

            source = source.OrderBy(sortString);

            return await source.ToListAsync(cancellationToken);

        }

    }
}
