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 Order2Test {

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


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

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

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

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

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

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

        secondToAct.addFood(1);
        int initialPrestige = secondToAct.getPrestigeValue();

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

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

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

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

        secondToAct.addPrestige(3);

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

        assertEquals(0, secondToAct.getFoodValue());
        assertEquals(1, secondToAct.getPrestigeValue());
    }

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

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

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

        order.push(firstToAct);

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

    @Test
    void thirdPlayerThrows() {
        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);
        Order2 order = new Order2(players);

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

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

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

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

        Order2 order = new Order2(players);

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

        assertTrue((firstOut == p1 && secondOut == p2) || (firstOut == p2 && secondOut == p1));
        assertNull(order.pull());
    }


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

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

        order.push(p1);

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