package createMessages_test

import "seekia/internal/cryptography/mlkem"
import "seekia/internal/cryptography/nacl"
import "seekia/internal/cryptography/csidh"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/messaging/readMessages"
import "seekia/internal/messaging/createMessages"
import "seekia/internal/messaging/inbox"

import "time"
import "testing"

func TestReadMessagePublicData(t *testing.T){

	messageNetworkType, err := helpers.GetRandomByteWithinRange(1, 2)
	if (err != nil) {
		t.Fatal("Failed to get random network type: " + err.Error())
	}

	identityType, err := helpers.GetRandomItemFromList([]string{"Mate", "Moderator"})
	if (err != nil) {
		t.Fatal("Failed to get random identity type: " + err.Error())
	}

	senderIdentityPublicKey, senderIdentityPrivateKey, err := identity.GetNewRandomPublicPrivateIdentityKeys()
	if (err != nil) {
		t.Fatal("Failed to derive identity keys: " + err.Error())
	}

	senderIdentityHash, err := identity.ConvertIdentityKeyToIdentityHash(senderIdentityPublicKey, identityType)
	if (err != nil) {
		t.Fatal("Failed to derive identity hash: " + err.Error())
	}

	recipientInbox, err := inbox.GetNewRandomInbox()
	if (err != nil) {
		t.Fatal("GetNewRandomInbox failed: " + err.Error())
	}

	recipientIdentityHash, err := identity.GetNewRandomIdentityHash(true, identityType)
	if (err != nil) {
		t.Fatal("Failed to get random identity hash: " + err.Error())
	}

	senderLatestChatKeysUpdateTime := int64(12345678900)

	recipientNaclKey, err := nacl.GetNewRandomPublicNaclKey()
	if (err != nil) {
		t.Fatal("GetNewRandomPublicNaclKey failed: " + err.Error())
	}
	
	recipientMlkemKey, err := mlkem.GetNewRandomPublicMlkemKey()
	if (err != nil) {
		t.Fatal("GetNewRandomPublicMlkemKey failed: " + err.Error())
	}

	recipientCsidhKey, _, err := csidh.GetNewRandomPublicPrivateCsidhKeys()
	if (err != nil) {
		t.Fatal("GetNewRandomPublicPrivateCsidhKeys failed: " + err.Error())
	}

	messageCreationTime := time.Now().Unix()

	senderCurrentSecretInboxSeed, err := inbox.GetNewRandomSecretInboxSeed()
	if (err != nil) {
		t.Fatal("GetNewRandomSecretInboxSeed failed: " + err.Error())
	}

	senderNextSecretInboxSeed, err := inbox.GetNewRandomSecretInboxSeed()
	if (err != nil) {
		t.Fatal("GetNewRandomSecretInboxSeed failed: " + err.Error())
	}

	senderDeviceIdentifier, err := helpers.GetNewRandomDeviceIdentifier()
	if (err != nil) {
		t.Fatal("GetNewRandomDeviceIdentifier failed: " + err.Error())
	}

	testCommunication := "This is a test message."

	doubleSealedKeysSealerKey, err := helpers.GetNewRandom32ByteArray()
	if (err != nil) {
		t.Fatal("GetNewRandom32ByteArray failed: " + err.Error())
	}

	finalMessage, messageHash, err := createMessages.CreateChatMessage(messageNetworkType, senderIdentityHash, senderIdentityPublicKey, senderIdentityPrivateKey, messageCreationTime, senderCurrentSecretInboxSeed, senderNextSecretInboxSeed, senderDeviceIdentifier, senderLatestChatKeysUpdateTime, testCommunication, recipientIdentityHash, recipientInbox, recipientNaclKey, recipientMlkemKey, recipientCsidhKey, doubleSealedKeysSealerKey)
	if (err != nil) {
		t.Fatal("Failed to create chat message: " + err.Error())
	}

	ableToRead, messageHash_Received, messageVersion_Received, messageNetworkType_Received, recipientInbox_Received, _, _, _, _, _, _, err := readMessages.ReadChatMessagePublicDataAndHash(true, finalMessage)
	if (err != nil) {
		t.Fatal("Failed to read message public data: " + err.Error())
	}
	if (ableToRead == false){
		t.Fatal("Failed to read message public data.")
	}
	if (messageVersion_Received != 1){
		t.Fatal("Message version does not match.")
	}
	if (messageNetworkType_Received != messageNetworkType){
		t.Fatal("Message network type does not match.")
	}
	if (messageHash != messageHash_Received){
		t.Fatal("Message hash does not match.")
	}
	if (recipientInbox != recipientInbox_Received){
		t.Fatal("Message recipient identity hash does not match.")
	}
}


func TestEncryptDecryptMessage(t *testing.T) {

	messageNetworkType, err := helpers.GetRandomByteWithinRange(1, 2)
	if (err != nil) {
		t.Fatal("Failed to get random network type: " + err.Error())
	}

	identityType, err := helpers.GetRandomItemFromList([]string{"Mate", "Moderator"})
	if (err != nil) {
		t.Fatal("Failed to get random identity type: " + err.Error())
	}

	senderIdentityPublicKey, senderIdentityPrivateKey, err := identity.GetNewRandomPublicPrivateIdentityKeys()
	if (err != nil) {
		t.Fatal("Failed to derive identity keys: " + err.Error())
	}

	senderIdentityHash, err := identity.ConvertIdentityKeyToIdentityHash(senderIdentityPublicKey, identityType)
	if (err != nil) {
		t.Fatal("Failed to derive identity hash: " + err.Error())
	}

	recipientInbox, err := inbox.GetNewRandomInbox()
	if (err != nil) {
		t.Fatal("GetNewRandomInbox failed: " + err.Error())
	}

	recipientIdentityHash, err := identity.GetNewRandomIdentityHash(true, identityType)
	if (err != nil) {
		t.Fatal("Failed to get random identity hash: " + err.Error())
	}

	senderLatestChatKeysUpdateTime := int64(1234567899900)

	recipientNaclPublicKey, recipientNaclPrivateKey, err := nacl.GetNewRandomPublicPrivateNaclKeys()
	if (err != nil) {
		t.Fatal("Failed to derive Nacl keys: " + err.Error())
	}

	recipientMlkemPublicKey, recipientMlkemPrivateKey, err := mlkem.GetNewRandomPublicPrivateMlkemKeys()
	if (err != nil) {
		t.Fatal("Failed to derive Mlkem keys: " + err.Error())
	}

	recipientCsidhPublicKey, recipientCsidhPrivateKey, err := csidh.GetNewRandomPublicPrivateCsidhKeys()
	if (err != nil) {
		t.Fatal("Failed to derive Csidh keys: " + err.Error())
	}

	messageCreationTime := time.Now().Unix()

	senderCurrentSecretInboxSeed, err := inbox.GetNewRandomSecretInboxSeed()
	if (err != nil) {
		t.Fatal("GetNewRandomSecretInboxSeed failed: " + err.Error())
	}

	senderNextSecretInboxSeed, err := inbox.GetNewRandomSecretInboxSeed()
	if (err != nil) {
		t.Fatal("GetNewRandomSecretInboxSeed failed: " + err.Error())
	}

	senderDeviceIdentifier, err := helpers.GetNewRandomDeviceIdentifier()
	if (err != nil) {
		t.Fatal("GetNewRandomDeviceIdentifier failed: " + err.Error())
	}

	testCommunication := "This is a test message."

	doubleSealedKeysSealerKey, err := helpers.GetNewRandom32ByteArray()
	if (err != nil) {
		t.Fatal("GetNewRandom32ByteArray failed: " + err.Error())
	}

	finalMessage, messageHash, err := createMessages.CreateChatMessage(messageNetworkType, senderIdentityHash, senderIdentityPublicKey, senderIdentityPrivateKey, messageCreationTime, senderCurrentSecretInboxSeed, senderNextSecretInboxSeed, senderDeviceIdentifier, senderLatestChatKeysUpdateTime, testCommunication, recipientIdentityHash, recipientInbox, recipientNaclPublicKey, recipientMlkemPublicKey, recipientCsidhPublicKey, doubleSealedKeysSealerKey,)
	if (err != nil) {
		t.Fatal("Failed to create chat message: " + err.Error())
	}

	newChatKeySet := readMessages.ChatKeySet{

		NaclPublicKey: recipientNaclPublicKey,
		NaclPrivateKey: recipientNaclPrivateKey,
		MlkemPrivateKey: recipientMlkemPrivateKey,
		CsidhPrivateKey: recipientCsidhPrivateKey,
	}
	newRecipientChatDecryptionKeySetsList := []readMessages.ChatKeySet{newChatKeySet}

	ableToRead, messageHash_Received, messageVersion, messageNetworkType_Received, messageCipherKey, senderIdentityHash_Received, recipientIdentityHash_Received, messageCreationTime_Received, communication_Received, senderCurrentSecretInboxSeed_Received, senderNextSecretInboxSeed_Received, senderDeviceIdentifier_Received, senderLatestChatKeysUpdateTime_Received, err := readMessages.ReadChatMessage(finalMessage, doubleSealedKeysSealerKey, newRecipientChatDecryptionKeySetsList)
	if (err != nil) {
		t.Fatal("Failed to read chat message: " + err.Error())
	}
	if (ableToRead == false) {
		t.Fatal("Failed to read chat message.")
	} 
	if (messageVersion != 1){
		t.Fatal("Message version is not valid.")
	}
	if (messageNetworkType_Received != messageNetworkType){
		t.Fatal("Message network type does not match.")
	}
	if (messageHash != messageHash_Received){
		t.Fatal("Message hash does not match.")
	}
	if (senderIdentityHash != senderIdentityHash_Received){
		t.Fatal("Sender identity hash does not match.")
	}
	if (recipientIdentityHash != recipientIdentityHash_Received){
		t.Fatal("Recipient identity hash does not match.")
	}
	if (messageCreationTime != messageCreationTime_Received){
		t.Fatal("Message creation time is incorrect.")
	}

	if (testCommunication != communication_Received){
		t.Fatal("Message communication does not match.")
	}

	if (senderCurrentSecretInboxSeed != senderCurrentSecretInboxSeed_Received){
		t.Fatal("senderCurrentSecretInboxSeed does not match.")
	}

	if (senderNextSecretInboxSeed != senderNextSecretInboxSeed_Received){
		t.Fatal("senderNextSecretInboxSeed does not match.")
	}

	if (senderLatestChatKeysUpdateTime != senderLatestChatKeysUpdateTime_Received){
		t.Fatal("Sender latest chat keys update time does not match.")
	}

	if (senderDeviceIdentifier != senderDeviceIdentifier_Received){
		t.Fatal("Sender device identifier does not match.")
	}

	if (len(messageCipherKey) != 32){
		t.Fatal("ReadChatMessage returning invalid messageCipherKey: Invalid length.")
	}

	messageCipherKeyArray := [32]byte(messageCipherKey)
	
	ableToRead, messageHash_Received, messageVersion_Received, messageNetworkType_Received, senderIdentityHash_Received, communication_Received, err := readMessages.ReadChatMessageWithCipherKey(finalMessage, messageCipherKeyArray)
	if (err != nil){
		t.Fatal("ReadChatMessageWithCipherKey failed: " + err.Error())
	}
	if (ableToRead == false){
		t.Fatal("ReadChatMessageWithCipherKey failed.")
	}
	if (messageVersion_Received != 1){
		t.Fatal("ReadChatMessageWithCipherKey failed: returning mismatched version.")
	}
	if (messageNetworkType_Received != messageNetworkType){
		t.Fatal("ReadChatMessageWithCipherKey failed: returning mismatched network type.")
	}
	if (messageHash != messageHash_Received){
		t.Fatal("ReadChatMessageWithCipherKey failed: returning mismatched messageHash.")
	}

	if (senderIdentityHash != senderIdentityHash_Received){
		t.Fatal("ReadChatMessageWithCipherKey failed: Sender identity hash does not match.")
	}

	if (testCommunication != communication_Received){
		t.Fatal("ReadChatMessageWithCipherKey failed: Message communication does not match.")
	}
}

