package pl.edu.pw.mini.jk.sg.game.graph.moves.many.advanceable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Optional;

import org.junit.Test;

import com.google.common.collect.ImmutableList;

import junit.framework.TestCase;
import pl.edu.pw.mini.jk.sg.game.common.Accident;
import pl.edu.pw.mini.jk.sg.game.common.TwoPlayerPayoffInfo;
import pl.edu.pw.mini.jk.sg.game.configuration.DiscreteProbabilityFunction;
import pl.edu.pw.mini.jk.sg.game.configuration.Edge;
import pl.edu.pw.mini.jk.sg.game.configuration.GraphDescription;
import pl.edu.pw.mini.jk.sg.game.configuration.StaticGameConfiguration;
import pl.edu.pw.mini.jk.sg.game.graph.advanceable.AdvanceableGraphGameConfiguration;

public class ManyMovesAdvanceableStateGameTest {

	private static StaticGameConfiguration getGameConfiguration() {
		java.util.List<Edge> edges = new ArrayList<>();

		for (int i = 0; i < 4; i++) {
			edges.add(new Edge(i, 4));
			edges.add(new Edge(4, i));
		}

		return new StaticGameConfiguration(new GraphDescription(5, edges), Arrays.asList(2, 3), Arrays.asList(1),
				new int[][] { { 10 }, { 15 } }, new int[][] { { 8 }, { 10 } },
				new int[][] { { 1 }, { 2 }, { 3 }, { 4 }, { 5 } }, new int[][] { { 5 }, { 4 }, { 3 }, { 2 }, { 1 } }, 1,
				3, DiscreteProbabilityFunction.instance(), 0, 0);
	}

	public static ManyMovesAdvanceableStateGame getTestGame() {
		return new ManyMovesAdvanceableStateGame(new AdvanceableGraphGameConfiguration(getGameConfiguration(), 2),
				Optional.empty(), false);
	}

	@Test
	public void testOneMove() {
		ManyMovesAdvanceableStateGame game = getTestGame();

		game.playDefenderMove(new SingleUnitDestination(4));
		game.playAttackerMove(new SingleUnitDestination(1));
		final TwoPlayerPayoffInfo pi = game.finishRound();
		final AdvanceableMultiMoveDefenderState ds = game.getCurrentState().getDefenderVisibleState();
		final AdvanceableMultiMoveAttackerState as = game.getCurrentState().getAttackerVisibleState();
		
		TestCase.assertEquals(new TwoPlayerPayoffInfo(0, 0, 0, 0), pi);
		TestCase.assertEquals(ImmutableList.of(4,0,0), ds.getUnitPositions());
		TestCase.assertEquals(ImmutableList.of(1,1), as.getUnitPositions());
		TestCase.assertEquals(1, ds.getCurrentUnit());
		TestCase.assertEquals(1, as.getCurrentUnit());
		TestCase.assertEquals(0, ds.getTimeStep());
	}
	
	@Test
	public void testOneStep() {
		ManyMovesAdvanceableStateGame game = getTestGame();

		game.playDefenderMove(new SingleUnitDestination(4));
		game.playAttackerMove(new SingleUnitDestination(4));
		final TwoPlayerPayoffInfo pi1 = game.finishRound();
		game.playDefenderMove(new SingleUnitDestination(0));
		game.playAttackerMove(new SingleUnitDestination(1));
		final TwoPlayerPayoffInfo pi2 = game.finishRound();
		game.playDefenderMove(new SingleUnitDestination(0));
		game.playAttackerMove(new SingleUnitDestination(-1));
		final TwoPlayerPayoffInfo pi3 = game.finishRound();
		
		final AdvanceableMultiMoveDefenderState ds = game.getCurrentState().getDefenderVisibleState();
		final AdvanceableMultiMoveAttackerState as = game.getCurrentState().getAttackerVisibleState();
		
		
		TestCase.assertEquals(new TwoPlayerPayoffInfo(0, 0, 0, 0), pi1);
		TestCase.assertEquals(new TwoPlayerPayoffInfo(0, 0, 0, 0), pi2);
		TestCase.assertEquals(new TwoPlayerPayoffInfo(5, -1, 1, 0), pi3);
		

		TestCase.assertEquals(ImmutableList.of(4,0,0), ds.getUnitPositions());
		TestCase.assertEquals(ImmutableList.of(4,1), as.getUnitPositions());
		TestCase.assertEquals(0, ds.getCurrentUnit());
		TestCase.assertEquals(0, as.getCurrentUnit());
		TestCase.assertEquals(1, ds.getTimeStep());
		TestCase.assertEquals(ImmutableList.of(new Accident(0, 0, 4, false)), game.getPreviousAccidents());
		TestCase.assertEquals(5.0, game.getDefenderResult(), 1e-6);
		TestCase.assertEquals(-1, game.getAttackerResult(), 1e-6);
	}

	@Test
	public void defenderStateAdvanceTest() {
		ManyMovesAdvanceableStateGame game = getTestGame();
		final AdvanceableMultiMoveDefenderState ds = game.getDefenderInitialState();
		final AdvanceableMultiMoveDefenderState ds1 = ds.advance(new SingleUnitDestination(0));
		final AdvanceableMultiMoveDefenderState ds2 = ds1.advance(new SingleUnitDestination(4));
		final AdvanceableMultiMoveDefenderState ds3 = ds2.advance(new SingleUnitDestination(0));
		
		TestCase.assertEquals(1, ds1.getCurrentUnit());
		TestCase.assertEquals(2, ds2.getCurrentUnit());
		TestCase.assertEquals(1, ds3.getTimeStep());
		TestCase.assertEquals(0, ds3.getCurrentUnit());
		TestCase.assertEquals(ImmutableList.of(0,0,0), ds.getUnitPositions());
		TestCase.assertEquals(ImmutableList.of(0,0,0), ds1.getUnitPositions());
		TestCase.assertEquals(ImmutableList.of(0,4,0), ds2.getUnitPositions());
		TestCase.assertEquals(ImmutableList.of(0,4,0), ds3.getUnitPositions());
	}
	@Test
	public void attackerStateAdvanceTest() {
		ManyMovesAdvanceableStateGame game = getTestGame();
		final AdvanceableMultiMoveAttackerState ds = game.getAttackerInitialState();
		final AdvanceableMultiMoveAttackerState ds1 = ds.advance(new SingleUnitDestination(1));
		final AdvanceableMultiMoveAttackerState ds2 = ds1.advance(new SingleUnitDestination(4));
		final AdvanceableMultiMoveAttackerState ds3 = ds2.advance(new SingleUnitDestination(-1));
		
		TestCase.assertEquals(1, ds1.getCurrentUnit());
		TestCase.assertEquals(2, ds2.getCurrentUnit());
		TestCase.assertEquals(0, ds3.getCurrentUnit());
		TestCase.assertEquals(ImmutableList.of(1,1), ds.getUnitPositions());
		TestCase.assertEquals(ImmutableList.of(1,1), ds1.getUnitPositions());
		TestCase.assertEquals(ImmutableList.of(1,4), ds2.getUnitPositions());
		TestCase.assertEquals(ImmutableList.of(1,4), ds3.getUnitPositions());
	}
	
}
