using System;
using System.Buffers.Text;
using System.Linq;
using System.Text;

namespace Mirea.Api.Security.Services;

public static class GeneratorKey
{
    public static string GenerateAlphaNumeric(int size, string? excludes = null, string? includes = null)
    {
        var random = new Random();
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

        var charsForGenerate = excludes?
            .Aggregate(chars, (current, ex) => current.Replace(ex.ToString(), string.Empty)) ?? chars;

        if (!string.IsNullOrEmpty(includes))
            charsForGenerate = includes
                .Aggregate(charsForGenerate, (current, include) =>
                    current.Contains(include) ? current : current + include);

        return new string(Enumerable.Repeat(charsForGenerate, size)
            .Select(s => s[random.Next(s.Length)])
            .ToArray());
    }

    public static string GenerateAlphaNumericBase32Compatible(int size, string? excludes = null,
        string? includes = null) =>
        GenerateAlphaNumeric(size, excludes + "0189", includes);

    public static ReadOnlySpan<byte> GenerateBytes(int size)
    {
        var key = new byte[size];
        using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
        rng.GetNonZeroBytes(key);
        return key;
    }

    public static string GenerateBase64(int size) =>
        Convert.ToBase64String(GenerateBytes(size));

    public static string GenerateString(int size)
    {
        var randomBytes = GenerateBytes(size);
        Span<byte> utf8Bytes = new byte[Base64.GetMaxEncodedToUtf8Length(randomBytes.Length)];

        Base64.EncodeToUtf8(randomBytes, utf8Bytes, out _, out _);
        return Encoding.UTF8.GetString(utf8Bytes);
    }
}