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.ArrayList;
import java.util.Arrays;
import java.util.NoSuchElementException;
import static org.junit.jupiter.api.Assertions.*;

class Order3Test {

    @Test
    @DisplayName("Testing Order3 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 Order3(players);});
    }

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

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

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

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

    @Test
    void secondReturnNoEffect() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        Order3 order = new Order3(players);

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

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

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

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

    @Test
    void thirdReturnPaysFoodAndLosesPrestige() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        Order3 order = new Order3(players);

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

        thirdToAct.addFood(1);

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

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

    @Test
    void thirdReturnWithoutFoodNoEffect() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        Order3 order = new Order3(players);

        Player firstToAct = order.pull();
        Player secondToAct = order.pull();
        Player thirdToAct = 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 firstReturnWithBuilding() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        ArrayList<Player> players = new ArrayList<>();
        players.add(p1);
        players.add(p2);
        players.add(p3);
        Order3 order = new Order3(players);

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

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

        order.push(firstToAct);

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

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

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

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

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

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

        Order3 order = new Order3(players);

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

        assertTrue(firstOut == p1 || firstOut == p2 || firstOut == p3);
        assertTrue(secondOut == p1 || secondOut == p2 || secondOut == p3);
        assertTrue(thirdOut == p1 || thirdOut == p2 || thirdOut == p3);
        assertNotEquals(firstOut, secondOut);
        assertNotEquals(firstOut, thirdOut);
        assertNotEquals(secondOut, thirdOut);
        assertNull(order.pull());
    }

    @Test
    void getFirst() {
        Player p1 = new Player("p1");
        Player p2 = new Player("p2");
        Player p3 = new Player("p3");
        Order3 order = new Order3(new ArrayList<>(Arrays.asList(p1, p2, p3)));


        order.pull();
        order.pull();
        order.pull();
        assertNull(order.getFirst());

        order.push(p1);

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

