using System;
using System.Security.Cryptography;


namespace Quadarax.Foundation.Core.Value.Generators
{
   
    public class TinyHash : IIdGenerator<string>
    {
        #region *** Constants ***
        public const string DefaultCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        public const int DefaultLength = 5;
        #endregion

        #region *** Private fields ***
        private readonly int _length;
        private readonly string _charset;
        #endregion

        #region *** Constructors ***
        public TinyHash(string charset, int length)
        {
            if (string.IsNullOrEmpty(charset)) throw new ArgumentNullException(nameof(charset));
            if (length < 1) throw new ArgumentOutOfRangeException(nameof(length));

            _charset = charset;
            _length = length;
        }

        public TinyHash(int length) : this(DefaultCharset, length)
        {
        }

        public TinyHash() : this(DefaultCharset, DefaultLength)
        {
        }
        #endregion


        #region *** Public Operations ***
        public string NewId()
        {
            var outputChars = new char[_length];
    
            using var rnd = RandomNumberGenerator.Create();
            var diff = _charset.Length;
            var upperBound = uint.MaxValue / diff * diff;
            var randomBuffer = new byte[sizeof(int)];

            for (var i = 0; i < outputChars.Length; i++)
            {
                // Generate a fair, random number between minIndex and maxIndex
                uint randomUInt;
                do
                {
                    rnd.GetBytes(randomBuffer);
                    randomUInt = BitConverter.ToUInt32(randomBuffer, 0);
                }
                while (randomUInt >= upperBound);
                var charIndex = (int)(randomUInt % diff);

                // Set output character based on random index
                outputChars[i] = _charset[charIndex];
            }

            return new string(outputChars);
        }
        #endregion
    }
}
