package it.polimi.ingsw.gc14.Model.Orders;

import it.polimi.ingsw.gc14.Model.Cards.BuildingCard;
import it.polimi.ingsw.gc14.Model.Player;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.*;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import static org.junit.jupiter.api.Assertions.*;

class Order5Test {

    @Test
    @DisplayName("Testing Order5 constructor with wrong number of player")
    void constructorTest() {
        Player p1 = new Player("p1");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        assertThrows(NoSuchElementException.class, () -> {new Order5(players);});
    }

    @Test
    void firstReturnGetsFood() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        Player firstToAct = order.pull();
        order.pull();
        order.pull();
        order.pull();
        order.pull();

        int initialFood = firstToAct.getFoodValue();
        order.push(firstToAct);

        assertEquals(initialFood + 3, firstToAct.getFoodValue());
        assertEquals(firstToAct, order.getFirst());
    }

    @Test
    void secondReturnGetsFood() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        Player firstToAct = order.pull();
        Player secondToAct = order.pull();
        order.pull();
        order.pull();
        order.pull();

        int initialFood = secondToAct.getFoodValue();

        order.push(firstToAct);
        order.push(secondToAct);

        assertEquals(initialFood + 1, secondToAct.getFoodValue());
    }

    @Test
    void thirdReturnNoEffect() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        Player firstToAct = order.pull();
        Player secondToAct = order.pull();
        Player thirdToAct = order.pull();
        order.pull();
        order.pull();

        int initialFood = thirdToAct.getFoodValue();
        int initialPrestige = thirdToAct.getPrestigeValue();

        order.push(firstToAct);
        order.push(secondToAct);
        order.push(thirdToAct);

        assertEquals(initialFood, thirdToAct.getFoodValue());
        assertEquals(initialPrestige, thirdToAct.getPrestigeValue());
    }

    @Test
    void fourthReturnNoEffect() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        Player firstToAct = order.pull();
        Player secondToAct = order.pull();
        Player thirdToAct = order.pull();
        Player fourthToAct = order.pull();
        order.pull();

        int initialFood = fourthToAct.getFoodValue();
        int initialPrestige = fourthToAct.getPrestigeValue();

        order.push(firstToAct);
        order.push(secondToAct);
        order.push(thirdToAct);
        order.push(fourthToAct);

        assertEquals(initialFood, fourthToAct.getFoodValue());
        assertEquals(initialPrestige, fourthToAct.getPrestigeValue());
    }

    @Test
    void fifthReturnPaysFoodAndLosesPrestige() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        Player firstToAct = order.pull();
        Player secondToAct = order.pull();
        Player thirdToAct = order.pull();
        Player fourthToAct = order.pull();
        Player fifthToAct = order.pull();

        fifthToAct.addFood(1);

        order.push(firstToAct);
        order.push(secondToAct);
        order.push(thirdToAct);
        order.push(fourthToAct);
        order.push(fifthToAct);

        assertEquals(0, fifthToAct.getFoodValue());
        assertEquals(-2, fifthToAct.getPrestigeValue());
    }

    @Test
    void fifthReturnWithoutFoodNoEffect() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        Player firstToAct = order.pull();
        Player secondToAct = order.pull();
        Player thirdToAct = order.pull();
        Player fourthToAct = order.pull();
        Player fifthToAct = order.pull();

        int initialFood = fifthToAct.getFoodValue();
        int initialPrestige = fifthToAct.getPrestigeValue();

        order.push(firstToAct);
        order.push(secondToAct);
        order.push(thirdToAct);
        order.push(fourthToAct);
        order.push(fifthToAct);

        assertEquals(initialFood, fifthToAct.getFoodValue());
        assertEquals(initialPrestige, fifthToAct.getPrestigeValue());
    }

    @Test
    void firstReturnWithBuilding() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        Player firstToAct = order.pull();
        order.pull();
        order.pull();
        order.pull();
        order.pull();

        firstToAct.buildingCards.add(new BuildingCard(3, 1, 1, 2));

        order.push(firstToAct);

        assertEquals(4, firstToAct.getFoodValue());
    }

    @Test
    void secondReturnWithBuilding() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        Player firstToAct = order.pull();
        Player secondToAct = order.pull();
        order.pull();
        order.pull();
        order.pull();

        secondToAct.buildingCards.add(new BuildingCard(3, 1, 1, 2));

        order.push(firstToAct);
        order.push(secondToAct);

        assertEquals(2, secondToAct.getFoodValue());
    }

    @Test
    void sixthPlayerThrows() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        Player p6 = new Player("p6");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);
        Order5 order = new Order5(players);

        order.pull();
        order.pull();
        order.pull();
        order.pull();
        order.pull();

        order.push(p1);
        order.push(p2);
        order.push(p3);
        order.push(p4);
        order.push(p5);

        assertThrows(IndexOutOfBoundsException.class, () -> order.push(p6));
    }

    @Test
    void constructorLoadsPlayers() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        players.add(p4);
        players.add(p5);

        Order5 order = new Order5(players);

        Player firstOut = order.pull();
        Player secondOut = order.pull();
        Player thirdOut = order.pull();
        Player fourthOut = order.pull();
        Player fifthOut = order.pull();

        assertTrue(firstOut == p1 || firstOut == p2 || firstOut == p3 || firstOut == p4 || firstOut == p5);
        assertTrue(secondOut == p1 || secondOut == p2 || secondOut == p3 || secondOut == p4 || secondOut == p5);
        assertTrue(thirdOut == p1 || thirdOut == p2 || thirdOut == p3 || thirdOut == p4 || thirdOut == p5);
        assertTrue(fourthOut == p1 || fourthOut == p2 || fourthOut == p3 || fourthOut == p4 || fourthOut == p5);
        assertTrue(fifthOut == p1 || fifthOut == p2 || fifthOut == p3 || fifthOut == p4 || fifthOut == p5);

        assertNotEquals(firstOut, secondOut);
        assertNotEquals(firstOut, thirdOut);
        assertNotEquals(firstOut, fourthOut);
        assertNotEquals(firstOut, fifthOut);
        assertNotEquals(secondOut, thirdOut);
        assertNotEquals(secondOut, fourthOut);
        assertNotEquals(secondOut, fifthOut);
        assertNotEquals(thirdOut, fourthOut);
        assertNotEquals(thirdOut, fifthOut);
        assertNotEquals(fourthOut, fifthOut);

        assertEquals(null, order.pull());
    }

    @Test
    void getFirst() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Player p4 = new Player("p4");
        Player p5 = new Player("p5");
        Order5 order = new Order5(new ArrayList<>(Arrays.asList(p1,p2,p3,p4,p5)));
        Player firstOut = order.pull();
        Player secondOut = order.pull();
        Player thirdOut = order.pull();
        Player fourthOut = order.pull();
        Player fifthOut = order.pull();
        assertNull(order.getFirst());

        order.push(p1);

        assertEquals(p1, order.getFirst());
        assertEquals(p1, order.getFirst());
    }
}

















