using System.Buffers;
using System.Text.RegularExpressions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace strings;

class Program
{
    static void Main()
    {
        var s = "X-FooBar"u8;
        BenchmarkRunner.Run<Benchmarks>();
    }
}

[ShortRunJob]
[MemoryDiagnoser]
public class Benchmarks
{
    [Params("abcd66", "ABCD66", "1abcd", "abcd1", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0")]
    public string Values { get; set; } = null!;

    //[Benchmark] public bool NormalFor() => ProductId.Valid_NormalFor(Values);
    //[Benchmark] public bool NormalForEach() => ProductId.Valid_NormalForEach(Values);
    //[Benchmark] public bool LINQAll() => ProductId.Valid_LINQAll(Values);
    //[Benchmark] public bool LINQAny() => ProductId.Valid_LINQAny(Values);
    //[Benchmark] public bool SpanContains() => ProductId.Valid_SpanContains(Values);
    //[Benchmark] public bool SearchValuesContains() => ProductId.Valid_SearchValuesContains(Values);

    //[Benchmark] public bool RegexNormal() => ProductId.Valid_RegexNormal(Values);
    //[Benchmark] public bool RegexCompiled() => ProductId.Valid_RegexCompiled(Values);
    //[Benchmark] public bool RegexGenerated() => ProductId.Valid_RegexGenerated(Values);
}

public partial class ProductId
{
    public string Value { get; init; } = null!;

    ProductId() { }

    public static ProductId? Parse(string? value)
    {
        if (string.IsNullOrEmpty(value))
            return null;
        if (!Valid(value))
            return null;
        return new ProductId() { Value = value };
    }

    static readonly char[] ValidCharactersUpper = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X'];
    static readonly char[] ValidCharactersLower = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x'];
    static readonly char[] ValidCharactersNumbers = ['2', '3', '4', '5', '6', '7', '8', '9'];
    static readonly char[] ValidCharacters = [.. ValidCharactersUpper, .. ValidCharactersLower, .. ValidCharactersNumbers];

    static bool Valid(string value) => Valid_NormalFor(value);

    public static bool Valid_NormalFor(string value)
    {
        for (var i = 0; i < value.Length; i++)
        {
            if (!ValidCharacters.Contains(value[i]))
            {
                return false;
            }
        }
        return true;
    }

    public static bool Valid_NormalForEach(string value)
    {
        foreach (var c in value)
        {
            if (!ValidCharacters.Contains(c))
            {
                return false;
            }
        }
        return true;
    }

    public static bool Valid_LINQAll(string value)
    {
        return value.All(x => ValidCharacters.Contains(x));
    }

    public static bool Valid_LINQAny(string value)
    {
        return value.Any(x => !ValidCharacters.Contains(x));
    }

    public static bool Valid_SpanContains(string value)
    {
        return !value.AsSpan().ContainsAnyExcept(ValidCharacters);
    }

    static readonly SearchValues<char> ValidSearchValues = SearchValues.Create(ValidCharacters);
    public static bool Valid_SearchValuesContains(string value)
    {
        return !value.AsSpan().ContainsAnyExcept(ValidSearchValues);
    }

    static readonly Regex ValidRegex = new Regex($"^[{ValidCharacters}]*$");
    public static bool Valid_RegexNormal(string value)
    {
        return ValidRegex.IsMatch(value);
    }

    static readonly Regex ValidRegexCompiled = new Regex($"^[{ValidCharacters}]*$", RegexOptions.Compiled);
    public static bool Valid_RegexCompiled(string value)
    {
        return ValidRegexCompiled.IsMatch(value);
    }

    [GeneratedRegex(@"^[ABCDEFGHJKMNPQRSTUVWXabcdefghjkmnpqrstuvwx23456789]*$")]
    private static partial Regex ValidRegexGenerated();
    public static bool Valid_RegexGenerated(string value)
    {
        return ValidRegexGenerated().IsMatch(value);
    }
}
