package geniusweb.protocol.session;

import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import geniusweb.actions.PartyId;
import geniusweb.inform.Agreements;
import geniusweb.issuevalue.Bid;
import geniusweb.issuevalue.DiscreteValue;
import geniusweb.issuevalue.Value;
import geniusweb.references.Parameters;
import geniusweb.references.PartyRef;
import geniusweb.references.PartyWithParameters;
import geniusweb.references.PartyWithProfile;
import geniusweb.references.ProfileRef;
import tudelft.utilities.junit.GeneralTests;

public class SessionResultTest extends GeneralTests<SessionResult> {
	private final ObjectMapper jackson = new ObjectMapper();
	private final RuntimeException error = new RuntimeException("test");

	private final String ISSUE1 = "issue1";
	private SessionResult result1, result1a, result2, result3, result4;
	private String jsonstring = "{\"participants\":{\"party2\":{\"party\":{\"partyref\":\"party2\",\"parameters\":{}},\"profile\":\"profile2\"},\"party1\":{\"party\":{\"partyref\":\"party1\",\"parameters\":{}},\"profile\":\"profile1\"}},\"agreements\":{\"party2\":{\"issuevalues\":{\"issue1\":\"a\"}},\"party1\":{\"issuevalues\":{\"issue1\":\"a\"}}},\"penalties\":{\"party2\":0.0,\"party1\":0.0},\"error\":null}";
	private Map<PartyId, Double> nopenalties = new HashMap<>();
	private Map<PartyId, Double> penalties = new HashMap<>();

	private PartyId PARTY1 = new PartyId("party1");
	private PartyId PARTY2 = new PartyId("party2");
	private PartyId PARTY3 = new PartyId("party3");

	@Before
	public void before() throws URISyntaxException, JsonProcessingException {
		penalties.put(PARTY1, 0.1d);
		penalties.put(PARTY2, 0.2d);
		nopenalties.put(PARTY1, 0d);
		nopenalties.put(PARTY2, 0d);

		String errorstring = "\"error\":{\"java.lang.RuntimeException\":"
				+ jackson.writeValueAsString(error) + "}";
		// System.out.println(errorstring);

		PartyWithParameters party1 = new PartyWithParameters(
				new PartyRef("party1"), new Parameters());
		PartyWithParameters party2 = new PartyWithParameters(
				new PartyRef("party2"), new Parameters());

		PartyWithProfile partyprofile1 = new PartyWithProfile(party1,
				new ProfileRef("profile1"));
		PartyWithProfile partyprofile2 = new PartyWithProfile(party2,
				new ProfileRef("profile2"));

		Map<String, Value> issuevalues1 = new HashMap<>();
		issuevalues1.put(ISSUE1, new DiscreteValue("a"));
		Bid bid1 = new Bid(issuevalues1);
		Agreements agreement1 = new Agreements().with(new Agreements(bid1,
				new HashSet<>(Arrays.asList(PARTY1, PARTY2))));

		// different order but that shouldn't matter
		Map<String, Value> issuevalues2 = new HashMap<>();
		issuevalues2.put(ISSUE1, new DiscreteValue("b"));
		Bid bid2 = new Bid(issuevalues2);
		Agreements agreement2 = new Agreements().with(new Agreements(bid2,
				new HashSet<>(Arrays.asList(PARTY1, PARTY3))));

		Map<PartyId, PartyWithProfile> partiesmap = new HashMap<>();
		partiesmap.put(PARTY1, partyprofile1);
		partiesmap.put(PARTY2, partyprofile2);

		Map<PartyId, PartyWithProfile> partiesmap2 = new HashMap<>();
		partiesmap2.put(PARTY1, partyprofile2);
		partiesmap2.put(PARTY3, partyprofile1);

		result1 = new SessionResult(partiesmap, agreement1, nopenalties, null);
		result1a = new SessionResult(partiesmap, agreement1, nopenalties, null);
		result2 = new SessionResult(partiesmap, agreement2, nopenalties, null);
		result3 = new SessionResult(partiesmap2, agreement1, nopenalties, null);
		result4 = new SessionResult(partiesmap2, agreement1, penalties, null);

		// IGNORE ERROR for now, it fails somewhere deep in maven suddenly.
		// result4 = new SessionResult(Arrays.asList(partyprofile1,
		// partyprofile2), bid1, error);
	}

	@Override
	public List<List<SessionResult>> getGeneralTestData() {
		return Arrays.asList(Arrays.asList(result1, result1a),
				Arrays.asList(result2), Arrays.asList(result3),
				Arrays.asList(result4));
	}

	@Override
	public List<String> getGeneralTestStrings() {
		return Arrays.asList(
				"SessionResult.*party2.*profile2.*,.*party1.*profile1.*Agreements.*Bid.*issue1=\"a\".*0\\.0.*0\\.0.*null.*",
				"SessionResult.*party2.*profile2.*,.*party1.*profile1.*Agreements.*Bid.*issue1=\"b\".*0\\.0.*0\\.0.*null.*",
				"SessionResult.*party1.*profile2.*,.*party3.*profile1.*Agreements.*Bid.*issue1=\"a\".*0\\.0.*0\\.0.*null.*",
				"SessionResult.*party1.*profile2.*,.*party3.*profile1.*Agreements.*Bid.*issue1=\"a\".*party2.*0\\.2.*party1.*0\\.1.*null.*"

		);
	}

	@Test
	public void serializeTest() throws JsonProcessingException {
		System.out.println(jackson.writeValueAsString(result1));
		assertEquals(jsonstring, jackson.writeValueAsString(result1));
	}

	@Test
	public void deserializeTest() throws IOException {
		SessionResult act = jackson.readValue(jsonstring, SessionResult.class);
		assertEquals(result1, act);
	}

}
