package org.hyperledger.indy.sdk.crypto;

import org.hyperledger.indy.sdk.IndyIntegrationTest;
import org.hyperledger.indy.sdk.IndyIntegrationTestWithSingleWallet;
import org.hyperledger.indy.sdk.InvalidParameterException;
import org.hyperledger.indy.sdk.InvalidStructureException;
import org.hyperledger.indy.sdk.wallet.WalletItemNotFoundException;
import org.json.JSONObject;
import org.junit.Test;
import org.json.JSONArray;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import static org.hamcrest.CoreMatchers.isA;
import static org.junit.Assert.*;

public class PackUnpackMessageTest extends IndyIntegrationTestWithSingleWallet {
	private String message = "hello world";

	@Test
	public void testPackMessageAnoncryptWorks() throws Exception {
		JSONArray receivers = new JSONArray(new String[]{VERKEY_MY1, VERKEY_MY2, VERKEY_TRUSTEE});

		byte[] packedMessage = Crypto.packMessage(wallet, receivers.toString(), null, message.getBytes()).get();

		assertNotNull(packedMessage);
	}

	@Test
	public void testPackMessageAuthcryptWorks() throws Exception {
		JSONArray receivers = new JSONArray(new String[]{VERKEY_MY1});

		String senderVerkey = Crypto.createKey(wallet, MY1_IDENTITY_KEY_JSON).get();

		byte[] packedMessage = Crypto.packMessage(wallet, receivers.toString(), senderVerkey, message.getBytes()).get();

		assertNotNull(packedMessage);
	}

	@Test
	public void testPackErrorsWithUnknownSenderVerkey() throws Exception {
		JSONArray receivers = new JSONArray(new String[]{VERKEY_MY1});

		thrown.expect(ExecutionException.class);
		thrown.expectCause(isA(WalletItemNotFoundException.class));

		Crypto.packMessage(wallet, receivers.toString(), IndyIntegrationTest.VERKEY_MY2, message.getBytes()).get();

		// this assert should never trigger since packMessage should throw exception
		assertTrue(false);
	}

	@Test
	public void testPackMessageErrorsWithNoReceivers() throws Exception {
		JSONArray receivers = new JSONArray();

		thrown.expect(ExecutionException.class);
		thrown.expectCause(isA(InvalidParameterException.class));

		Crypto.packMessage(wallet, receivers.toString(), null, message.getBytes()).get();

		// this assert should never trigger since unpackMessage should throw exception
		assertTrue(false);
	}

	@Test
	public void testPackMessageErrorsInvalidReceivers() throws Exception {
		JSONArray receivers = new JSONArray(new String[]{"IndyIntegrationTest.VERKEY_MY1"});

		thrown.expect(ExecutionException.class);
		thrown.expectCause(isA(InvalidStructureException.class));

		Crypto.packMessage(wallet, receivers.toString(), null, message.getBytes()).get();

		// this assert should never trigger since unpackMessage should throw exception
		assertTrue(false);
	}

	@Test
	public void testUnpackMessageErrorsWithInvalidPackedMessageStructure() {
		String packedMessage = "jibberish";

		thrown.expect(ExecutionException.class);
		thrown.expectCause(isA(InvalidStructureException.class));

		try {
			CompletableFuture<byte[]> future = Crypto.unpackMessage(wallet, packedMessage.getBytes());
			assertTrue(future.isCompletedExceptionally());
		} catch (Exception e) {
			// expected
			System.err.println("testUnpackMessageErrorsWithInvalidPackedMessageStructure threw " + e);
			return;
		}
		// this assert should never trigger since unpackMessage should throw exception
		assertTrue(false);
	}

	@Test
	public void testUnpackMessageAnoncryptWorks() throws Exception {
		String receiverVerkey = Crypto.createKey(wallet, "{}").get();

		JSONArray receivers = new JSONArray(new String[]{receiverVerkey, VERKEY_TRUSTEE});

		byte[] packedMessage = Crypto.packMessage(wallet, receivers.toString(), null, message.getBytes()).get();

		byte[] unpackedMessageBytes = Crypto.unpackMessage(wallet, packedMessage).get();

		JSONObject unpackedMessage = new JSONObject(new String(unpackedMessageBytes));

		assertEquals(message, unpackedMessage.getString("message"));
		assertEquals(receiverVerkey, unpackedMessage.getString("recipient_verkey"));
		assertFalse(unpackedMessage.has("sender_verkey"));
	}

	@Test
	public void testUnpackMesssageAuthcryptWorks() throws Exception {
		String receiverVerkey = Crypto.createKey(wallet, "{}").get();
		String senderVerkey = Crypto.createKey(wallet, "{}").get();

		JSONArray receivers = new JSONArray(new String[]{receiverVerkey});

		byte[] packedMessage = Crypto.packMessage(wallet, receivers.toString(), senderVerkey, message.getBytes()).get();
		byte[] unpackedMessageBytes = Crypto.unpackMessage(wallet, packedMessage).get();

		JSONObject unpackedMessage = new JSONObject(new String(unpackedMessageBytes));

		assertEquals(message, unpackedMessage.getString("message"));
		assertEquals(receiverVerkey, unpackedMessage.getString("recipient_verkey"));
		assertEquals(senderVerkey, unpackedMessage.getString("sender_verkey"));
	}
}

@@ -2820,16 +2820,33 @@
 ucture()
+ throws Exception
  %7B%0A%09%09Str
@@ -2950,33 +2950,33 @@
 (isA(Invalid
-Structure
+Parameter
 Exception.cl
@@ -2989,52 +2989,8 @@
 %0A%0A%09%09
-try %7B%0A%09%09%09CompletableFuture%3Cbyte%5B%5D%3E future = 
 Cryp
@@ -3043,209 +3043,16 @@
 s())
-;%0A%09%09%09assertTrue(future.isCompletedExceptionally
+.get
 ()
-)
 ;%0A
-%09%09%7D catch (Exception e) %7B%0A%09%09%09// expected%0A%09%09%09System.err.println(%22testUnpackMessageErrorsWithInvalidPackedMessageStructure threw %22 + e);%0A%09%09%09return;%0A%09%09%7D
 %0A%09%09/

fix expected exception