using Quadarax.Foundation.Core.Value.Generators;

namespace qdr.fnd.core.test.Value.Generators
{
    public class TinyHashTest
    {
        [Test(TestOf = typeof(TinyHash))]
        public void ImplementsInterface()
        {
            Assert.IsInstanceOf<IIdGenerator<string>>(new TinyHash());
        }

        [Test(TestOf = typeof(TinyHash))]
        public void ConstructorFail()
        {
            // ReSharper disable once ObjectCreationAsStatement
            Assert.Throws<ArgumentNullException>(() => new TinyHash(null!, 5));
            // ReSharper disable once ObjectCreationAsStatement
            Assert.Throws<ArgumentNullException>(() => new TinyHash(string.Empty, 5));
            // ReSharper disable once ObjectCreationAsStatement
            Assert.Throws<ArgumentOutOfRangeException>(() => new TinyHash("A", 0));
            // ReSharper disable once ObjectCreationAsStatement
            Assert.Throws<ArgumentOutOfRangeException>(() => new TinyHash("A", -1));
            // ReSharper disable once ObjectCreationAsStatement
            Assert.Throws<ArgumentOutOfRangeException>(() => new TinyHash( 0));
            // ReSharper disable once ObjectCreationAsStatement
            Assert.Throws<ArgumentOutOfRangeException>(() => new TinyHash(-1));
        }

        [Test(TestOf = typeof(TinyHash))]
        public void GenerateNumberDefault()
        {
            var generator = new TinyHash();
            var result1 = generator.NewId();
            var result2 = generator.NewId();

            Assert.IsNotNull(result1);
            Assert.IsNotNull(result2);
            Assert.That(result2, Is.Not.EqualTo(result1));
            Assert.That(result1.Length, Is.EqualTo(TinyHash.DefaultLength));
            Assert.That(result2.Length, Is.EqualTo(TinyHash.DefaultLength));
            Assert.That(ValueAmongChars(result1, TinyHash.DefaultCharset), "value has some chars out of defined charset.");
            Assert.That(ValueAmongChars(result2, TinyHash.DefaultCharset), "value has some chars out of defined charset.");
        }

        [Test(TestOf = typeof(TinyHash))]
        public void GenerateNumberSpecificLength()
        {
            var length = 3;
            var generator = new TinyHash(length);
            var result1 = generator.NewId();
            var result2 = generator.NewId();

            Assert.IsNotNull(result1);
            Assert.IsNotNull(result2);
            Assert.That(result2, Is.Not.EqualTo(result1));
            Assert.That(result1.Length, Is.EqualTo(length));
            Assert.That(result2.Length, Is.EqualTo(length));
            Assert.That(ValueAmongChars(result1, TinyHash.DefaultCharset), "value has some chars out of defined charset.");
            Assert.That(ValueAmongChars(result2, TinyHash.DefaultCharset), "value has some chars out of defined charset.");
        }
        [Test(TestOf = typeof(TinyHash))]
        public void GenerateNumberCustomCharset()
        {
            var charset = "xyz";
            var generator = new TinyHash(charset, TinyHash.DefaultLength);
            var result1 = generator.NewId();
            var result2 = generator.NewId();

            Assert.IsNotNull(result1);
            Assert.IsNotNull(result2);
            Assert.That(result2, Is.Not.EqualTo(result1));
            Assert.That(result1.Length, Is.EqualTo(TinyHash.DefaultLength));
            Assert.That(result2.Length, Is.EqualTo(TinyHash.DefaultLength));
            Assert.That(ValueAmongChars(result1,charset), "value has some chars out of defined charset.");
            Assert.That(ValueAmongChars(result2, charset), "value has some chars out of defined charset.");
        }

        #region *** Private methods ***
        private bool ValueAmongChars(string value, string charset)
        {
            foreach (var c in value)
            {
                if (!charset.Contains(c)) return false;
            }
            return true;
        }
        #endregion
    }
}
