using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace Masuit.Tools
{
    public static class IEnumerableExtensions
    {
        /// 
        /// 按字段属性判等取交集
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func condition)
        {
            return first.Where(f => second.Any(s => condition(f, s)));
        }
        /// 
        /// 按字段属性判等取交集
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector)
        {
            return first.IntersectBy(second, keySelector, null);
        }
        /// 
        /// 按字段属性判等取交集
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer? comparer)
        {
            if (first == null)
                throw new ArgumentNullException(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            return IntersectByIterator(first, second, keySelector, comparer);
        }
        private static IEnumerable IntersectByIterator(IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer)
        {
            var set = new HashSet(second.Select(keySelector), comparer);
            foreach (var source in first)
            {
                if (set.Remove(keySelector(source)))
                    yield return source;
            }
        }
        /// 
        /// 多个集合取交集元素
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectAll(this IEnumerable> source)
        {
            return source.Aggregate((current, item) => current.Intersect(item));
        }
        /// 
        /// 多个集合取交集元素
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectAll(this IEnumerable> source, Func keySelector)
        {
            return source.Aggregate((current, item) => current.IntersectBy(item, keySelector));
        }
        /// 
        /// 多个集合取交集元素
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectAll(this IEnumerable> source, Func keySelector, IEqualityComparer comparer)
        {
            return source.Aggregate((current, item) => current.IntersectBy(item, keySelector, comparer));
        }
        /// 
        /// 多个集合取交集元素
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectAll(this IEnumerable> source, IEqualityComparer comparer)
        {
            return source.Aggregate((current, item) => current.Intersect(item, comparer));
        }
        /// 
        /// 按字段属性判等取差集
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func condition)
        {
            return first.Where(f => !second.Any(s => condition(f, s)));
        }
#if NET6_0_OR_GREATER
#else
        /// 
        /// 按字段去重
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector)
        {
            var hash = new HashSet();
            return source.Where(p => hash.Add(keySelector(p)));
        }
        /// 
        /// 按字段属性判等取交集
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector)
        {
            return first.IntersectBy(second, keySelector, null);
        }
        /// 
        /// 按字段属性判等取交集
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer? comparer)
        {
            if (first == null)
                throw new ArgumentNullException(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            return IntersectByIterator(first, second, keySelector, comparer);
        }
        private static IEnumerable IntersectByIterator(IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer)
        {
            var set = new HashSet(second, comparer);
            foreach (var source in first)
            {
                if (set.Remove(keySelector(source)))
                    yield return source;
            }
        }
        /// 
        /// 按字段属性判等取差集
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector)
        {
            return first.ExceptBy(second, keySelector, null);
        }
        /// 
        /// 按字段属性判等取差集
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer? comparer)
        {
            if (first == null)
                throw new ArgumentNullException(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            return ExceptByIterator(first, second, keySelector, comparer);
        }
        private static IEnumerable ExceptByIterator(IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer comparer)
        {
            var set = new HashSet(second, comparer);
            foreach (var source in first)
            {
                if (set.Add(keySelector(source)))
                    yield return source;
            }
        }
#endif
        /// 
        /// 添加多个元素
        /// 
        /// 
        /// 
        /// 
        public static void AddRange(this ICollection @this, params T[] values)
        {
            foreach (var obj in values)
            {
                @this.Add(obj);
            }
        }
        /// 
        /// 添加多个元素
        /// 
        /// 
        /// 
        /// 
        public static void AddRange(this ICollection @this, IEnumerable values)
        {
            foreach (var obj in values)
            {
                @this.Add(obj);
            }
        }
        /// 
        /// 添加多个元素
        /// 
        /// 
        /// 
        /// 
        public static void AddRange(this ConcurrentBag @this, params T[] values)
        {
            foreach (var obj in values)
            {
                @this.Add(obj);
            }
        }
        /// 
        /// 添加多个元素
        /// 
        /// 
        /// 
        /// 
        public static void AddRange(this ConcurrentQueue @this, params T[] values)
        {
            foreach (var obj in values)
            {
                @this.Enqueue(obj);
            }
        }
        /// 
        /// 添加符合条件的多个元素
        /// 
        /// 
        /// 
        /// 
        /// 
        public static void AddRangeIf(this ICollection @this, Func predicate, params T[] values)
        {
            foreach (var obj in values)
            {
                if (predicate(obj))
                {
                    @this.Add(obj);
                }
            }
        }
        /// 
        /// 添加符合条件的多个元素
        /// 
        /// 
        /// 
        /// 
        /// 
        public static void AddRangeIf(this ConcurrentBag @this, Func predicate, params T[] values)
        {
            foreach (var obj in values)
            {
                if (predicate(obj))
                {
                    @this.Add(obj);
                }
            }
        }
        /// 
        /// 添加符合条件的多个元素
        /// 
        /// 
        /// 
        /// 
        /// 
        public static void AddRangeIf(this ConcurrentQueue @this, Func predicate, params T[] values)
        {
            foreach (var obj in values)
            {
                if (predicate(obj))
                {
                    @this.Enqueue(obj);
                }
            }
        }
        /// 
        /// 添加不重复的元素
        /// 
        /// 
        /// 
        /// 
        public static void AddRangeIfNotContains(this ICollection @this, params T[] values)
        {
            foreach (T obj in values)
            {
                if (!@this.Contains(obj))
                {
                    @this.Add(obj);
                }
            }
        }
        /// 
        /// 移除符合条件的元素
        /// 
        /// 
        /// 
        /// 
        public static void RemoveWhere(this ICollection @this, Func @where)
        {
            foreach (var obj in @this.Where(where).ToList())
            {
                @this.Remove(obj);
            }
        }
        /// 
        /// 在元素之后添加元素
        /// 
        /// 
        /// 
        /// 条件
        /// 值
        public static void InsertAfter(this IList list, Func condition, T value)
        {
            foreach (var item in list.Select((item, index) => new
            {
                item,
                index
            }).Where(p => condition(p.item)).OrderByDescending(p => p.index))
            {
                if (item.index + 1 == list.Count)
                {
                    list.Add(value);
                }
                else
                {
                    list.Insert(item.index + 1, value);
                }
            }
        }
        /// 
        /// 在元素之后添加元素
        /// 
        /// 
        /// 
        /// 索引位置
        /// 值
        public static void InsertAfter(this IList list, int index, T value)
        {
            foreach (var item in list.Select((v, i) => new
            {
                Value = v,
                Index = i
            }).Where(p => p.Index == index).OrderByDescending(p => p.Index))
            {
                if (item.Index + 1 == list.Count)
                {
                    list.Add(value);
                }
                else
                {
                    list.Insert(item.Index + 1, value);
                }
            }
        }
        /// 
        /// 转HashSet
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static HashSet ToHashSet(this IEnumerable source, Func selector)
        {
            var set = new HashSet();
            set.UnionWith(source.Select(selector));
            return set;
        }
        /// 
        /// 遍历IEnumerable
        /// 
        /// 
        /// 回调方法
        /// 
        public static void ForEach(this IEnumerable objs, Action action)
        {
            foreach (var o in objs)
            {
                action(o);
            }
        }
        /// 
        /// 异步foreach
        /// 
        /// 
        /// 
        /// 最大并行数
        /// 
        /// 
        /// 
        public static async Task ForeachAsync(this IEnumerable source, Func action, int maxParallelCount, CancellationToken cancellationToken = default)
        {
            if (Debugger.IsAttached)
            {
                foreach (var item in source)
                {
                    await action(item);
                }
                return;
            }
            var list = new List();
            foreach (var item in source)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }
                list.Add(action(item));
                if (list.Count >= maxParallelCount)
                {
                    await Task.WhenAll(list);
                    list.Clear();
                }
            }
            await Task.WhenAll(list);
        }
        /// 
        /// 异步foreach
        /// 
        /// 
        /// 
        /// 
        /// 
        public static Task ForeachAsync(this IEnumerable source, Func action, CancellationToken cancellationToken = default)
        {
            return ForeachAsync(source, action, source.Count(), cancellationToken);
        }
        /// 
        /// 异步Select
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static Task SelectAsync(this IEnumerable source, Func> selector)
        {
            return Task.WhenAll(source.Select(selector));
        }
        /// 
        /// 异步Select
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static Task SelectAsync(this IEnumerable source, Func> selector)
        {
            return Task.WhenAll(source.Select(selector));
        }
        /// 
        /// 异步Select
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 最大并行数
        /// 
        public static async Task> SelectAsync(this IEnumerable source, Func> selector, int maxParallelCount)
        {
            var results = new List();
            var tasks = new List>();
            foreach (var item in source)
            {
                var task = selector(item);
                tasks.Add(task);
                if (tasks.Count >= maxParallelCount)
                {
                    results.AddRange(await Task.WhenAll(tasks));
                    tasks.Clear();
                }
            }
            results.AddRange(await Task.WhenAll(tasks));
            return results;
        }
        /// 
        /// 异步Select
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 最大并行数
        /// 
        public static async Task> SelectAsync(this IEnumerable source, Func> selector, int maxParallelCount)
        {
            var results = new List();
            var tasks = new List>();
            int index = 0;
            foreach (var item in source)
            {
                var task = selector(item, index++);
                tasks.Add(task);
                if (tasks.Count >= maxParallelCount)
                {
                    results.AddRange(await Task.WhenAll(tasks));
                    tasks.Clear();
                }
            }
            results.AddRange(await Task.WhenAll(tasks));
            return results;
        }
        /// 
        /// 异步For
        /// 
        /// 
        /// 
        /// 
        /// 最大并行数
        /// 取消口令
        /// 
        public static async Task ForAsync(this IEnumerable source, Func selector, int maxParallelCount, CancellationToken cancellationToken = default)
        {
            int index = 0;
            if (Debugger.IsAttached)
            {
                foreach (var item in source)
                {
                    await selector(item, index);
                    index++;
                }
                return;
            }
            var list = new List();
            foreach (var item in source)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }
                list.Add(selector(item, index));
                Interlocked.Add(ref index, 1);
                if (list.Count >= maxParallelCount)
                {
                    await Task.WhenAll(list);
                    list.Clear();
                }
            }
            await Task.WhenAll(list);
        }
        /// 
        /// 异步For
        /// 
        /// 
        /// 
        /// 
        /// 取消口令
        /// 
        public static Task ForAsync(this IEnumerable source, Func selector, CancellationToken cancellationToken = default)
        {
            return ForAsync(source, selector, source.Count(), cancellationToken);
        }
        /// 
        /// 取最大值
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult MaxOrDefault(this IQueryable source, Expression> selector) => source.Select(selector).DefaultIfEmpty().Max();
        /// 
        /// 取最大值
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult MaxOrDefault(this IQueryable source, Expression> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Max();
        /// 
        /// 取最大值
        /// 
        /// 
        /// 
        /// 
        public static TSource MaxOrDefault(this IQueryable source) => source.DefaultIfEmpty().Max();
        /// 
        /// 取最大值
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TSource MaxOrDefault(this IQueryable source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Max();
        /// 
        /// 取最大值
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult MaxOrDefault(this IEnumerable source, Func selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Max();
        /// 
        /// 取最大值
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult MaxOrDefault(this IEnumerable source, Func selector) => source.Select(selector).DefaultIfEmpty().Max();
        /// 
        /// 取最大值
        /// 
        /// 
        /// 
        /// 
        public static TSource MaxOrDefault(this IEnumerable source) => source.DefaultIfEmpty().Max();
        /// 
        /// 取最大值
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TSource MaxOrDefault(this IEnumerable source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Max();
        /// 
        /// 取最小值
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult MinOrDefault(this IQueryable source, Expression> selector) => source.Select(selector).DefaultIfEmpty().Min();
        /// 
        /// 取最小值
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult MinOrDefault(this IQueryable source, Expression> selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Min();
        /// 
        /// 取最小值
        /// 
        /// 
        /// 
        /// 
        public static TSource MinOrDefault(this IQueryable source) => source.DefaultIfEmpty().Min();
        /// 
        /// 取最小值
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TSource MinOrDefault(this IQueryable source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Min();
        /// 
        /// 取最小值
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult MinOrDefault(this IEnumerable source, Func selector) => source.Select(selector).DefaultIfEmpty().Min();
        /// 
        /// 取最小值
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult MinOrDefault(this IEnumerable source, Func selector, TResult defaultValue) => source.Select(selector).DefaultIfEmpty(defaultValue).Min();
        /// 
        /// 取最小值
        /// 
        /// 
        /// 
        /// 
        public static TSource MinOrDefault(this IEnumerable source) => source.DefaultIfEmpty().Min();
        /// 
        /// 取最小值
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TSource MinOrDefault(this IEnumerable source, TSource defaultValue) => source.DefaultIfEmpty(defaultValue).Min();
        /// 
        /// 标准差
        /// 
        /// 
        /// 
        /// 
        /// 
        public static TResult StandardDeviation(this IEnumerable source, Func selector) where TResult : IConvertible
        {
            return StandardDeviation(source.Select(t => selector(t).ConvertTo())).ConvertTo();
        }
        /// 
        /// 标准差
        /// 
        /// 
        /// 
        /// 
        public static T StandardDeviation(this IEnumerable source) where T : IConvertible
        {
            return StandardDeviation(source.Select(t => t.ConvertTo())).ConvertTo();
        }
        /// 
        /// 标准差
        /// 
        /// 
        /// 
        public static double StandardDeviation(this IEnumerable source)
        {
            double result = 0;
            int count = source.Count();
            if (count > 1)
            {
                double avg = source.Average();
                double sum = source.Sum(d => (d - avg) * (d - avg));
                result = Math.Sqrt(sum / count);
            }
            return result;
        }
        /// 
        /// 随机排序
        /// 
        /// 
        /// 
        /// 
        public static IOrderedEnumerable OrderByRandom(this IEnumerable source)
        {
            return source.OrderBy(_ => Guid.NewGuid());
        }
        /// 
        /// 序列相等
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static bool SequenceEqual(this IEnumerable first, IEnumerable second, Func condition)
        {
            if (first is ICollection source1 && second is ICollection source2)
            {
                if (source1.Count != source2.Count)
                {
                    return false;
                }
                if (source1 is IList list1 && source2 is IList list2)
                {
                    int count = source1.Count;
                    for (int index = 0; index < count; ++index)
                    {
                        if (!condition(list1[index], list2[index]))
                        {
                            return false;
                        }
                    }
                    return true;
                }
            }
            using IEnumerator enumerator1 = first.GetEnumerator();
            using IEnumerator enumerator2 = second.GetEnumerator();
            while (enumerator1.MoveNext())
            {
                if (!enumerator2.MoveNext() || !condition(enumerator1.Current, enumerator2.Current))
                {
                    return false;
                }
            }
            return !enumerator2.MoveNext();
        }
        /// 
        /// 序列相等
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static bool SequenceEqual(this IEnumerable first, IEnumerable second, Func condition)
        {
            if (first is ICollection source1 && second is ICollection source2)
            {
                if (source1.Count != source2.Count)
                {
                    return false;
                }
                if (source1 is IList list1 && source2 is IList list2)
                {
                    int count = source1.Count;
                    for (int index = 0; index < count; ++index)
                    {
                        if (!condition(list1[index], list2[index]))
                        {
                            return false;
                        }
                    }
                    return true;
                }
            }
            using IEnumerator enumerator1 = first.GetEnumerator();
            using IEnumerator enumerator2 = second.GetEnumerator();
            while (enumerator1.MoveNext())
            {
                if (!enumerator2.MoveNext() || !condition(enumerator1.Current, enumerator2.Current))
                {
                    return false;
                }
            }
            return !enumerator2.MoveNext();
        }
        /// 
        /// 对比两个集合哪些是新增的、删除的、修改的
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 对比因素条件
        /// 
        public static (List adds, List remove, List updates) CompareChanges(this IEnumerable first, IEnumerable second, Func condition)
        {
            var add = first.ExceptBy(second, condition).ToList();
            var remove = second.ExceptBy(first, (s, f) => condition(f, s)).ToList();
            var update = first.IntersectBy(second, condition).ToList();
            return (add, remove, update);
        }
        /// 
        /// 对比两个集合哪些是新增的、删除的、修改的
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 对比因素条件
        /// 
        public static (List adds, List remove, List<(T1 first, T2 second)> updates) CompareChangesPlus(this IEnumerable first, IEnumerable second, Func condition)
        {
            var add = first.ExceptBy(second, condition).ToList();
            var remove = second.ExceptBy(first, (s, f) => condition(f, s)).ToList();
            var updates = first.IntersectBy(second, condition).Select(t1 => (t1, second.FirstOrDefault(t2 => condition(t1, t2)))).ToList();
            return (add, remove, updates);
        }
        /// 
        /// 将集合声明为非null集合
        /// 
        /// 
        /// 
        /// 
        public static List AsNotNull(this List list)
        {
            return list ?? new List();
        }
        /// 
        /// 将集合声明为非null集合
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable AsNotNull(this IEnumerable list)
        {
            return list ?? new List();
        }
        /// 
        /// 满足条件时执行筛选条件
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable WhereIf(this IEnumerable source, bool condition, Func where)
        {
            return condition ? source.Where(where) : source;
        }
        /// 
        /// 满足条件时执行筛选条件
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IEnumerable WhereIf