using System.Globalization;
using System.Threading;
using MajacloudSdk.Internal;
using NUnit.Framework;

namespace MajacloudSdk.Tests
{
    public class JsonTests
    {
        [Test]
        public void ParsesNestedDocumentAndRoundTrips()
        {
            var json = "{\"ok\":true,\"entry\":{\"rank\":null,\"score\":12.5,\"name\":\"N\\u00f6va \\ud83d\\ude00\"},\"list\":[1,2,3],\"big\":9007199254740993}";
            var node = JsonNode.Parse(json);
            Assert.IsTrue(node.GetBool("ok"));
            Assert.IsTrue(node["entry"]["rank"].IsNull);
            Assert.IsNull(node["entry"].GetNullableInt("rank"));
            Assert.AreEqual(12.5, node["entry"].GetDouble("score"));
            Assert.AreEqual("Növa 😀", node["entry"].GetString("name"));
            Assert.AreEqual(3, node.GetArray("list").Count);
            Assert.AreEqual(9007199254740993L, node.GetLong("big"));
            var again = JsonNode.Parse(node.ToJson());
            Assert.AreEqual(node.ToJson(), again.ToJson());
        }

        [Test]
        public void WriterIsCultureInvariant()
        {
            var original = Thread.CurrentThread.CurrentCulture;
            try
            {
                Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE");
                Assert.AreEqual("{\"a\":1.5,\"b\":2}", JsonNode.Object().Set("a", 1.5).Set("b", 2L).ToJson());
                Assert.AreEqual(1.5, JsonNode.Parse("{\"a\":1.5}").GetDouble("a"));
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = original;
            }
        }

        [Test]
        public void RejectsTrailingGarbageAndDepth()
        {
            Assert.Throws<JsonParseException>(() => JsonNode.Parse("{\"a\":1} x"));
            Assert.Throws<JsonParseException>(() => JsonNode.Parse("{\"a\":"));
            Assert.Throws<JsonParseException>(() => JsonNode.Parse("\"unterminated"));
            var deep = new string('[', 70) + new string(']', 70);
            Assert.Throws<JsonParseException>(() => JsonNode.Parse(deep));
        }

        [Test]
        public void MissingKeysReturnFallbacks()
        {
            var node = JsonNode.Parse("{\"s\":\"7\",\"b\":\"yes\",\"n\":3}");
            Assert.AreEqual("x", node.GetString("missing", "x"));
            Assert.AreEqual(7, node.GetInt("s"));
            Assert.IsTrue(node.GetBool("b"));
            Assert.AreEqual("3", node.GetString("n"));
            Assert.AreEqual(0, node["nope"]["deeper"].Count);
        }

        [Test]
        public void RawEmbedsFragments()
        {
            var body = JsonNode.Object().Set("data", JsonNode.Raw("{\"level\":3}")).Set("revision", 2L);
            Assert.AreEqual("{\"data\":{\"level\":3},\"revision\":2}", body.ToJson());
        }
    }

    public class CryptoTests
    {
        [Test]
        public void Base64UrlRoundTrip()
        {
            var bytes = new byte[] { 0, 1, 2, 250, 251, 252, 253, 254, 255 };
            var encoded = Base64Url.Encode(bytes);
            Assert.IsFalse(encoded.Contains("+") || encoded.Contains("/") || encoded.Contains("="));
            CollectionAssert.AreEqual(bytes, Base64Url.Decode(encoded));
        }

        [Test]
        public void PkceMatchesRfc7636Example()
        {
            Assert.AreEqual("E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM", Pkce.CreateChallenge("dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"));
            var verifier = Pkce.CreateVerifier();
            Assert.AreEqual(43, verifier.Length);
        }

        [Test]
        public void Sha256HexMatchesKnownVector()
        {
            Assert.AreEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", MajacloudCrypto.Sha256Hex("abc"));
        }
    }
}
