namespace Universal;

#if true
public static class Extensions
{
    public static bool In<T>(this T input, params T[] values)
    {
        return values.Contains(input);
    }

    public static void Foreach<T>(this IEnumerable<T> t, Action<T>? action = null)
    {
        foreach (var item in t)
            action?.Invoke(item);
    }

    public static void For<T>(this IEnumerable<T> t, uint startIndex, uint count, Action<T>? action = null)
    {
        T[] values = [.. t];
        uint endIndex = startIndex + count;
        for (uint i = startIndex; i < endIndex; i++)
            action?.Invoke(values[i]);
    }

    public static bool InRange<T>(this T t, T leftBorder, T rightBorder, bool startInclude = true, bool endInclude = true) where T : INumber<T>
    {

        if (startInclude)
        {
            if (t < leftBorder)
                return false;
        }
        else
        {
            if (t <= leftBorder)
                return false;
        }

        if (endInclude)
        {
            if (t > rightBorder)
                return false;
        }
        else
        {
            if (t >= rightBorder)
                return false;
        }

        return true;
    }


    public static void ForeachWhere<T>(this IEnumerable<T> t, Action<T> action, Func<T, bool> judger)
    {
        foreach (var item in t)
        {
            if (!judger.Invoke(item))
                continue;

            action.Invoke(item);
        }
    }

    public static bool TryForeach<T>(this IEnumerable<T> t, Func<T, bool> func)
    {
        foreach (var item in t)
        {
            if (!func.Invoke(item))
                return false;
        }

        return true;
    }

    public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> arr, int size)
    {
        for (var i = 0; i < arr.Count() / size + 1; i++)
            yield return arr.Skip(i * size).Take(size);
    }

    public static string ToBase64(this string input)
    {
        if (string.IsNullOrEmpty(input))
            return string.Empty;

        byte[] bytes = Encoding.ASCII.GetBytes(input);

        return Convert.ToBase64String(bytes);
    }

    public static string FromBase64(this string input)
    {
        if (string.IsNullOrEmpty(input))
            return string.Empty;

        byte[] bytes = Convert.FromBase64String(input);


        return Encoding.ASCII.GetString(bytes);
    }


    public static bool Split(this MemoryStream input, out List<byte[]>? output, int packLength = 4096)
    {
        output = default;

        if (packLength < 1)
            return false;

        Span<byte> t = input.ToArray();
        int count = t.Length / packLength;

        Span<byte> ts;
        output = [];
        for (int i = 0; i <= count; i++)
        {
            if (i == count)
            {
                ts = t.Slice(i * packLength);
                output.Add(ts.ToArray());
                break;
            }
            ts = t.Slice(i * packLength, packLength);
            output.Add(ts.ToArray());
        }

        return true;
    }
}
#endif

//Require C# 14+
#if NET10_0_OR_GREATER

public static class ExtensionTest
{
    extension<TSource>(TSource source) where TSource : INumber<TSource>
    {

        public bool InRange(TSource leftBorder, TSource rightBorder, bool startInclude = true, bool endInclude = true)
        {

            if (startInclude)
            {
                if (source < leftBorder)
                    return false;
            }
            else
            {
                if (source <= leftBorder)
                    return false;
            }

            if (endInclude)
            {
                if (source > rightBorder)
                    return false;
            }
            else
            {
                if (source >= rightBorder)
                    return false;
            }

            return true;
        }

    }

    extension(string input)
    {
        public string ToBase64()
        {
            if (string.IsNullOrEmpty(input))
                return string.Empty;

            byte[] bytes = Encoding.Default.GetBytes(input);

            return Convert.ToBase64String(bytes);
        }

        public string FromBase64()
        {
            if (string.IsNullOrEmpty(input))
                return string.Empty;

            byte[] bytes = Convert.FromBase64String(input);


            return Encoding.Default.GetString(bytes);
        }
    }

    extension<TSource>(TSource source) where TSource : struct
    {
        public bool ValueIn(params TSource[] values) => values.Contains(source);
    }

    extension<TSource>(TSource source) where TSource : class
    {
        public bool ReferenceIn(params TSource[] values) => values.Contains(source);
    }

    extension<TSource>(IEnumerable<TSource> sources)
    {
        public bool IsEmpty => !sources.Any();

        public void For(uint startIndex, uint count, Action<TSource> action)
        {
            TSource[] values = [.. sources];
            uint endIndex = startIndex + count;
            for (uint i = startIndex; i < endIndex; i++)
                action?.Invoke(values[i]);
        }

        public void Foreach(Action<TSource> action)
        {
            foreach (TSource source in sources)
                action?.Invoke(source);
        }

        public int ConditionForeach(Action<TSource> action, Func<TSource, bool> condition)
        {
            int count = 0;
            foreach (TSource source in sources)
            {
                if (!condition.Invoke(source))
                    continue;

                action.Invoke(source);
                count++;
            }
            return count;
        }

        public IEnumerable<IEnumerable<TSource>> Splits(int size)
        {
            for (var i = 0; i < sources.Count() / size + 1; i++)
                yield return sources.Skip(i * size).Take(size);
        }
    }
}
#endif