package com.priess.se.tdd.thirtyone;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import com.priess.se.tdd.thirtyone.Card;
import com.priess.se.tdd.thirtyone.Hand;
import com.priess.se.tdd.thirtyone.ThirtyOne;
import com.priess.se.tdd.thirtyone.ThirtyOneImpl;
import com.priess.se.tdd.thirtyone.Card.Color;
import com.priess.se.tdd.thirtyone.Card.Face;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.assertEquals;

@RunWith(Parameterized.class)
public class ThirtyOneTest {

	ThirtyOne t = new ThirtyOneImpl();

	@Parameterized.Parameter(0)
	public Hand hand;

	@Parameterized.Parameter(1)
	public double expectedValue;

	@Parameterized.Parameter(2)
	public boolean expectedLoss;

	@Parameterized.Parameter(3)
	public Class<? extends Exception> expectedException;

	@Rule
	public ExpectedException thrown = ExpectedException.none();

	@Parameterized.Parameters
	public static Collection<?> handsToTest() {
		return Arrays.asList(new Object[][]{
				// high card
				{new Hand(new Card(Color.KARO, Face.KOENIG), new Card(Color.PIK, Face.ASS), new Card(Color.HERZ, Face.KOENIG)), 11, true, null},
				// high card
				{new Hand(new Card(Color.KREUZ, Face.SIEBEN), new Card(Color.PIK, Face.ACHT), new Card(Color.KARO, Face.ZEHN)), 10, true, null},
				// 2 cards of one color
				{new Hand(new Card(Color.KARO, Face.KOENIG), new Card(Color.PIK, Face.ASS), new Card(Color.KARO, Face.NEUN)), 19, false, null},
				// 3 cards of one color
				{new Hand(new Card(Color.KARO, Face.DAME), new Card(Color.KARO, Face.BUBE), new Card(Color.KARO, Face.SIEBEN)), 27, false, null},
				// triplet
				{new Hand(new Card(Color.PIK, Face.NEUN), new Card(Color.KARO, Face.NEUN), new Card(Color.KREUZ, Face.NEUN)), 30.5, false, null},
				// triplet of aces
				{new Hand(new Card(Color.KREUZ, Face.ASS), new Card(Color.KARO, Face.ASS), new Card(Color.HERZ, Face.ASS)), 33, false, null},
				// invalid hand (null)
				{null, 0, true, IllegalArgumentException.class},
				// invalid hand (1 card)
				{new Hand(new Card(Color.KREUZ, Face.ASS)), 0, true, IllegalArgumentException.class},
				// invalid hand (4 cards)
				{new Hand(new Card(Color.KREUZ, Face.ASS), new Card(Color.PIK, Face.ASS), new Card(Color.KARO, Face.ASS), new Card(Color.HERZ, Face.ASS)), 0, true, IllegalArgumentException.class}
		});
	}

	@Test
	public void testValueOfHand() {
		if (expectedException != null) {
			thrown.expect(expectedException);
		}
		assertEquals("Incorrect hand value", expectedValue, t.valueOfHand(hand), 0);
	}

	@Test
	public void testIsOwnHandLosing() {
		Set<Hand> otherHands = new HashSet<Hand>();
		otherHands.add(new Hand(new Card(Color.KARO, Face.KOENIG), new Card(Color.KARO, Face.ASS), new Card(Color.KARO, Face.BUBE))); // 31
		otherHands.add(new Hand(new Card(Color.KARO, Face.ACHT), new Card(Color.KARO, Face.SIEBEN), new Card(Color.KARO, Face.NEUN))); // 24
		otherHands.add(new Hand(new Card(Color.KARO, Face.ACHT), new Card(Color.KARO, Face.SIEBEN), new Card(Color.PIK, Face.NEUN))); // 15

		if (expectedException != null) {
			thrown.expect(expectedException);
		}
		assertEquals("Unexpected result while determining loser", expectedLoss, t.isOwnHandLosing(hand, otherHands));
	}

}
