package randomvalues_test

import (
	b64 "encoding/base64"
	"fmt"
	"testing"

	"github.com/fiskerinc/cloud-services/pkg/testhelper"
	"github.com/fiskerinc/cloud-services/pkg/utils/randomvalues"
)

func TestRandomString(t *testing.T) {
	instance := randomvalues.NewGenerator("")

	type TestCase struct {
		Length int
	}

	tests := []TestCase{
		{
			Length: 12,
		},
		{
			Length: 32,
		},
		{
			Length: 10,
		},
		{
			Length: 100,
		},
	}

	for _, test := range tests {
		name := fmt.Sprintf("%v Length", test.Length)
		result, err := instance.GetString(test.Length)
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, name, nil, err)
		}
		if len(result) != test.Length {
			t.Errorf(testhelper.TestErrorTemplate, name, test.Length, len(result))
		}
	}
}

func TestRandomUInt64(t *testing.T) {
	generated := map[uint64]int{}
	instance := randomvalues.NewGenerator("")

	for i := 0; i < 1000; i++ {
		value, err := instance.GetUInt64()
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "RandomeUInt64", nil, err)
		}

		if result, ok := generated[value]; ok {
			generated[value] = result + 1
		} else {
			generated[value] = 1
		}
	}

	for key, value := range generated {
		if value > 1 {
			t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("%v occurance", key), 1, value)
		}
	}
}

func TestRandomHex(t *testing.T) {
	generated := map[string]int{}
	instance := randomvalues.NewGenerator("")

	for i := 0; i < 1000; i++ {
		value, err := instance.GetHex()
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "RandomeHex", nil, err)
		}

		if result, ok := generated[value]; ok {
			generated[value] = result + 1
		} else {
			generated[value] = 1
		}
	}

	for key, value := range generated {
		if value > 1 {
			t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("%v occurance", key), 1, value)
		}
	}
}

func TestUniformHex(t *testing.T) {
	repeats := 0

	generated := map[string]int{}
	instance := randomvalues.NewGenerator("")

	for i := 0; i < 1000000; i++ {
		value, err := instance.GetUniformDistHex()
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "UniformHex", nil, err)
		}

		if result, ok := generated[value]; ok {
			generated[value] = result + 1
			repeats += 1
		} else {
			generated[value] = 1
		}
	}

	for key, value := range generated {
		if value > 1 {
			t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("%v occurance", key), 1, value)
		}
	}

	if repeats > 0 {
		t.Errorf(testhelper.TestErrorTemplate, "Repeated", 0, repeats)
	}
}

func TestRandomBytes(t *testing.T) {
	keysize := 16
	generated := map[string]int{}
	instance := randomvalues.NewGenerator("")

	for i := 0; i < 1000; i++ {
		value, err := instance.GetBytes(keysize)
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "RandomBytes", nil, err)
		}

		val := b64.StdEncoding.EncodeToString(value)
		if result, ok := generated[val]; ok {
			generated[val] = result + 1
		} else {
			generated[val] = 1
		}
	}

	for key, value := range generated {
		if value > 1 {
			t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("%v occurance", key), 1, value)
		}
		decoded, err := b64.StdEncoding.DecodeString(key)
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "Decode string error", nil, err)
		}
		if len(decoded) != keysize {
			t.Errorf(testhelper.TestErrorTemplate, "Decoded string length", keysize, len(decoded))
		}
	}
}

func BenchmarkRandomString(b *testing.B) {
	instance := randomvalues.NewGenerator("")

	for i := 0; i < b.N; i++ {
		_, err := instance.GetString(32)
		if err != nil {
			b.Error(err)
		}
	}
}

func BenchmarkRandomUInt64(b *testing.B) {
	instance := randomvalues.NewGenerator("")

	for i := 0; i < b.N; i++ {
		_, err := instance.GetUInt64()
		if err != nil {
			b.Error(err)
		}
	}
}

func BenchmarkRandomHex(b *testing.B) {
	instance := randomvalues.NewGenerator("")

	for i := 0; i < b.N; i++ {
		_, err := instance.GetHex()
		if err != nil {
			b.Error(err)
		}
	}
}

func BenchmarkUniformDistHex(b *testing.B) {
	instance := randomvalues.NewGenerator("")

	for i := 0; i < b.N; i++ {
		_, err := instance.GetUniformDistHex()
		if err != nil {
			b.Error(err)
		}
	}
}
