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(t => !t.IsCompleted) >= maxParallelCount)
            {
                await Task.WhenAny(list);
                list.RemoveAll(t => t.IsCompleted);
            }
        }
        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)
    {
        first ??= new List();
        second ??= new List();
        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)
    {
        first ??= new List();
        second ??= new List();
        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