// ------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖，如有原作者特别声明，会在下方手动补充
// 此代码版权（除特别声明外的代码）归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库：https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库：https://github.com/kimdiego2098/ThingsGateway
// 使用文档：https://thingsgateway.cn/
// QQ群：605534569
// ------------------------------------------------------------------------------

using System.Buffers;

namespace ThingsGateway.Foundation.Extension.Generic;

/// <inheritdoc/>
public static class GenericExtensions
{
    /// <summary>
    /// 将一个数组进行扩充到指定长度，或是缩短到指定长度<br />
    /// </summary>
    public static T[] ArrayExpandToLength<T>(this T[] data, int length)
    {
        if (data == null)
        {
            return new T[length];
        }

        if (data.Length == length)
        {
            return data;
        }
        Array.Resize(ref data, length);

        return data;
    }

    /// <summary>
    /// 将一个数组进行扩充到指定长度，或是缩短到指定长度<br />
    /// </summary>
    public static Memory<T> ArrayExpandToLength<T>(this Memory<T> data, int length)
    {
        if (data.IsEmpty)
        {
            return Memory<T>.Empty;
        }

        if (data.Length == length)
        {
            return data;
        }

        var result = new T[length];
        data.Slice(0, Math.Min(data.Length, length)).CopyTo(result);
        return result;
    }

    /// <summary>
    /// 将一个数组进行扩充到指定长度，或是缩短到指定长度<br />
    /// </summary>
    public static ReadOnlyMemory<T> ArrayExpandToLength<T>(this ReadOnlyMemory<T> data, int length)
    {
        if (data.IsEmpty)
        {
            return ReadOnlyMemory<T>.Empty;
        }

        if (data.Length == length)
        {
            return data;
        }

        var result = new T[length];
        data.Slice(0, Math.Min(data.Length, length)).CopyTo(result);
        return result;
    }

    /// <summary>
    /// 将一个数组进行扩充到指定长度，或是缩短到指定长度<br />
    /// </summary>
    public static ReadOnlySpan<T> ArrayExpandToLength<T>(this ReadOnlySpan<T> data, int length)
    {
        if (data.IsEmpty)
        {
            return ReadOnlySpan<T>.Empty;
        }

        if (data.Length == length)
        {
            return data;
        }

        var result = new T[length];
        data.Slice(0, Math.Min(data.Length, length)).CopyTo(result);
        return result;
    }

    /// <summary>
    /// 将一个数组进行扩充到偶数长度<br />
    /// </summary>
    public static T[] ArrayExpandToLengthEven<T>(this T[] data)
    {
        if (data == null)
        {
            return Array.Empty<T>();
        }

        return data.Length % 2 == 1 ? data.ArrayExpandToLength(data.Length + 1) : data;
    }
    /// <summary>
    /// 将一个数组进行扩充到偶数长度<br />
    /// </summary>
    public static ReadOnlyMemory<T> ArrayExpandToLengthEven<T>(this ReadOnlyMemory<T> data)
    {
        if (data.IsEmpty)
        {
            return Array.Empty<T>();
        }

        return data.Length % 2 == 1 ? data.ArrayExpandToLength(data.Length + 1) : data;
    }

    /// <summary>
    /// 将一个数组进行扩充到偶数长度<br />
    /// </summary>
    public static Memory<T> ArrayExpandToLengthEven<T>(this Memory<T> data)
    {
        if (data.IsEmpty)
        {
            return Array.Empty<T>();
        }

        return data.Length % 2 == 1 ? data.ArrayExpandToLength(data.Length + 1) : data;
    }


    public static T[] ArrayRemoveBegin<T>(this T[] value, int length) => ArrayRemoveDouble(value, length, 0);
    public static T[] ArrayRemoveLast<T>(this T[] value, int length) => ArrayRemoveDouble(value, 0, length);

    public static ReadOnlySpan<T> ArrayRemoveBegin<T>(ReadOnlySpan<T> value, int length) => ArrayRemoveDouble(value, length, 0);
    public static ReadOnlySpan<T> ArrayRemoveLast<T>(ReadOnlySpan<T> value, int length) => ArrayRemoveDouble(value, 0, length);

    public static ReadOnlyMemory<T> ArrayRemoveBegin<T>(ReadOnlyMemory<T> value, int length) => ArrayRemoveDouble(value, length, 0);
    public static ReadOnlyMemory<T> ArrayRemoveLast<T>(ReadOnlyMemory<T> value, int length) => ArrayRemoveDouble(value, 0, length);

    /// <summary>
    /// 从数组中移除指定数量的元素，并返回新的数组
    /// </summary>
    /// <typeparam name="T">数组元素类型</typeparam>
    /// <param name="value">要移除元素的数组</param>
    /// <param name="leftLength">从左侧移除的元素个数</param>
    /// <param name="rightLength">从右侧移除的元素个数</param>
    /// <returns>移除元素后的新数组</returns>
    public static T[] ArrayRemoveDouble<T>(T[] value, int leftLength, int rightLength)
    {
        return ArrayRemoveDouble((ReadOnlySpan<T>)value, leftLength, rightLength).ToArray();
    }
    /// <summary>
    /// 从数组中移除指定数量的元素，并返回新的数组
    /// </summary>
    /// <typeparam name="T">数组元素类型</typeparam>
    /// <param name="value">要移除元素的数组</param>
    /// <param name="leftLength">从左侧移除的元素个数</param>
    /// <param name="rightLength">从右侧移除的元素个数</param>
    /// <returns>移除元素后的新数组</returns>
    public static ReadOnlySpan<T> ArrayRemoveDouble<T>(ReadOnlySpan<T> value, int leftLength, int rightLength)
    {
        // 如果输入数组为空或者剩余长度不足以移除左右两侧指定的元素，则返回空数组
        if (value.IsEmpty || value.Length <= leftLength + rightLength)
        {
            return Array.Empty<T>();
        }

        // 计算新数组的长度
        int newLength = value.Length - leftLength - rightLength;

        return value.Slice(leftLength, newLength);
    }
    /// <summary>
    /// 从数组中移除指定数量的元素，并返回新的数组
    /// </summary>
    /// <typeparam name="T">数组元素类型</typeparam>
    /// <param name="value">要移除元素的数组</param>
    /// <param name="leftLength">从左侧移除的元素个数</param>
    /// <param name="rightLength">从右侧移除的元素个数</param>
    /// <returns>移除元素后的新数组</returns>
    public static ReadOnlyMemory<T> ArrayRemoveDouble<T>(ReadOnlyMemory<T> value, int leftLength, int rightLength)
    {
        // 如果输入数组为空或者剩余长度不足以移除左右两侧指定的元素，则返回空数组
        if (value.IsEmpty || value.Length <= leftLength + rightLength)
        {
            return Array.Empty<T>();
        }

        // 计算新数组的长度
        int newLength = value.Length - leftLength - rightLength;

        return value.Slice(leftLength, newLength);
    }

    /// <summary>
    /// 将指定的数据按照指定长度进行分割
    /// </summary>
    public static List<T[]> ArraySplitByLength<T>(this T[] array, int length)
    {
        if (array == null || array.Length == 0)
        {
            return new List<T[]>();
        }

        int arrayLength = array.Length;
        int numArrays = (arrayLength + length - 1) / length; // 计算所需的数组数量

        List<T[]> objArrayList = new List<T[]>(numArrays);
        for (int i = 0; i < arrayLength; i += length)
        {
            int remainingLength = Math.Min(arrayLength - i, length);
            T[] destinationArray = new T[remainingLength];
            Array.Copy(array, i, destinationArray, 0, remainingLength);
            objArrayList.Add(destinationArray);
        }

        return objArrayList;
    }

    public static IEnumerable<List<T>> ChunkBetter<T>(this IEnumerable<T> source, int chunkSize)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (chunkSize <= 0) yield break;

        using var enumerator = source.GetEnumerator();
        while (enumerator.MoveNext())
        {
            var chunk = new List<T>(chunkSize) { enumerator.Current };
            for (int i = 1; i < chunkSize && enumerator.MoveNext(); i++)
            {
                chunk.Add(enumerator.Current);
            }

            yield return chunk;
        }
    }
    public static IEnumerable<ReadOnlyMemory<T>> ChunkBetter<T>(this ReadOnlyMemory<T> span, int groupSize)
    {
        for (int i = 0; i < span.Length; i += groupSize)
        {
            yield return span.Slice(i, Math.Min(groupSize, span.Length - i));
        }
    }

    public static IEnumerable<ReadOnlySequence<T>> ChunkBetter<T>(this ReadOnlySequence<T> sequence, int groupSize)
    {
        if (groupSize <= 0)
            throw new ArgumentOutOfRangeException(nameof(groupSize));

        var start = sequence.Start;
        var remaining = sequence.Length;

        while (remaining > 0)
        {
            var len = (int)Math.Min(groupSize, remaining);

            // 计算 chunk 的 end 位置
            var end = sequence.GetPosition(len, start);

            yield return sequence.Slice(start, end);

            // 移动起始位置
            start = end;
            remaining -= len;
        }
    }

    /// <summary>拷贝当前的实例数组，是基于引用层的浅拷贝，如果类型为值类型，那就是深度拷贝，如果类型为引用类型，就是浅拷贝</summary>
    public static T[] CopyArray<T>(this T[] value)
    {
        if (value == null)
        {
            return Array.Empty<T>();
        }

        T[] destinationArray = new T[value.Length];
        Array.Copy(value, destinationArray, value.Length);
        return destinationArray;
    }

    /// <summary>将一个一维数组中的所有数据按照行列信息拷贝到二维数组里，返回当前的二维数组</summary>
    public static T[,] CreateTwoArrayFromOneArray<T>(this T[] array, int row, int col)
    {
        T[,] arrayFromOneArray = new T[row, col];
        int index = 0;

        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                arrayFromOneArray[i, j] = array[index++];
                if (index >= array.Length) return arrayFromOneArray; // 防止数组越界
            }
        }

        return arrayFromOneArray;
    }



    /// <summary>
    /// 选择数组中的最后几个元素组成新的数组
    /// </summary>
    /// <typeparam name="T">数组元素类型</typeparam>
    /// <param name="value">输入数组</param>
    /// <param name="length">选择的元素个数</param>
    /// <returns>由最后几个元素组成的新数组</returns>
    public static T[] SelectLast<T>(this T[] value, int length) => ArrayRemoveBegin(value, value.Length - length);

    /// <summary>
    /// 从数组中获取指定索引开始的中间一段长度的子数组
    /// </summary>
    /// <typeparam name="T">数组元素类型</typeparam>
    /// <param name="value">输入数组</param>
    /// <param name="index">起始索引</param>
    /// <param name="length">选择的元素个数</param>
    /// <returns>中间指定长度的子数组</returns>
    public static T[] SelectMiddle<T>(this T[] value, int index, int length) => ArrayRemoveDouble(value, index, value.Length - index - length);
}
