package security_test

import (
	"testing"

	"github.com/fiskerinc/cloud-services/pkg/security"
	"github.com/fiskerinc/cloud-services/pkg/testhelper"
	"github.com/stretchr/testify/assert"
)

func TestEncrypt(t *testing.T) {
	key := []byte("MVYLJBSMa8YakAmm66f9carJp80r9S7h")
	encryptor, nonce, err := security.NewEncryptor(key, []byte("validate"), nil)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncrypt", nil, err)
	}
	encrypted := encryptor.EncryptChunk([]byte("Test Me"))

	decryptor, _, err := security.NewEncryptor(key, []byte("validate"), nonce) // use different instance to decrypt
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncrypt", nil, err)
	}
	decrypted, err := decryptor.DecryptChunk(encrypted)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncrypt", nil, err)
	}
	if string(decrypted) != "Test Me" {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncrypt", decrypted, len(decrypted))

	}
}

func TestEncryptStream(t *testing.T) {
	key := []byte("MVYLJBSMa8YakAmm66f9carJp80r9S7h")
	encryptor, _, err := security.NewEncryptor(key, []byte("validate"), nil)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncrypt", nil, err)
		return
	}
	unique_id := []byte("0123456789abcdef")
	stream, err := security.NewEncryptedStream(encryptor, security.WithUniqueId(unique_id))
	assert.Equal(t, err, nil, "failed to create string")
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncryptStream", nil, err)
		return
	}
	raw_data := []byte("testme test me testme testme")
	encrypted_stream := stream.Write(raw_data)

	stream1, err1 := security.NewEncryptedStream(encryptor)
	if stream1 == nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncrypt", nil, err1)
	}
	decryptedStream, err1 := stream1.Read(encrypted_stream)
	assert.Equal(t, string(decryptedStream), string(raw_data), "Strings don't match")
}

func TestEncryptStringToBase64(t *testing.T) {
	key := []byte("MVYLJBSMa8YakAmm66f9carJp80r9S7h")
	encryptor, _, err := security.NewEncryptor(key, []byte("validate"), nil)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncryptStringToBase64", nil, err)
	}

	encrypted := encryptor.EncryptStringToBase64("Test Me")
	if encrypted == "" {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncryptStringToBase64", "encrypted", encrypted)
	}
}

func TestDecryptBase64ToString(t *testing.T) {
	key := []byte("MVYLJBSMa8YakAmm66f9carJp80r9S7h")
	encryptor, nonce, err := security.NewEncryptor(key, []byte("validate"), nil)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestDecryptBase64ToString", nil, err)
	}

	encrypted := encryptor.EncryptStringToBase64("Test Me")
	if encrypted == "" {
		t.Errorf(testhelper.TestErrorTemplate, "TestDecryptBase64ToString", "encrypted", encrypted)
	}

	decryptor, _, err := security.NewEncryptor(key, []byte("validate"), nonce) // use different instance to decrypt
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestDecryptBase64ToString", nil, err)
	}

	decrypted, err := decryptor.DecryptBase64ToString(encrypted)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestDecryptBase64ToString", nil, err)
	}
	if decrypted != "Test Me" {
		t.Errorf(testhelper.TestErrorTemplate, "TestDecryptBase64ToString", "Test Me", decrypted)
	}
}

func BenchmarkEncryptConstruct(t *testing.B) {
	key := []byte("MVYLJBSMa8YakAmm66f9carJp80r9S7h")
	_, _, err := security.NewEncryptor(key, []byte("VALIDVIN123456789"), nil)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncrypt", nil, err)
	}
}

func BenchmarkEncryptConstructAndEncrypt(t *testing.B) {
	key := []byte("MVYLJBSMa8YakAmm66f9carJp80r9S7h")
	encryptor, _, err := security.NewEncryptor(key, []byte("VALIDVIN123456789"), nil)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestEncrypt", nil, err)
	}

	_ = encryptor.EncryptChunk([]byte("Test Me"))
}
