package Server;

import Server.Cards.Card;
import Server.Cards.CardDeck;
import Server.Cards.CharacterCard;
import Server.Cards.EventCard;
import Server.Utils.EventsManagerException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

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

class EventsSolverTest {

    static List<Player> players = new ArrayList<>();

    //Creating 4 players with a predefined tribe

    @BeforeAll
    public static void setUp(){
        BuildingManager buildingManager = new BuildingManager();

        Player winner = new Player("Winner", TotemColor.YELLOW);
        winner.addFood(10);
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;1;2;I;SHAMAN;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;2;2;I;SHAMAN;2;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;3;2;I;BUILDER;3;1"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;14;0;I;ARTIST;0;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;15;0;I;ARTIST;0;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;21;0;I;ARTIST;1;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;22;0;I;INVENTOR;9;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;23;4;I;INVENTOR;5;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;43;0;I;HUNTER;0;0"));
        winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;44;3;I;HUNTER;0;0"));
        players.add(winner);

        Player medium = new Player("Medium", TotemColor.RED);
        medium.addFood(10);
        medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;56;2;I;SHAMAN;3;0"));
        medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;34;2;I;BUILDER;3;1"));
        medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;32;3;I;GATHERER;3;0"));
        medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;33;0;I;ARTIST;0;0"));
        medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;45;3;I;HUNTER;0;0"));
        medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;72;0;I;ARTIST;9;0"));
        medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;73;4;I;INVENTOR;5;0"));
        players.add(medium);

        Player loser = new Player("Loser", TotemColor.BLUE);
        loser.addFood(2);
        loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;54;2;I;SHAMAN;2;0"));
        loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;36;2;I;BUILDER;3;1"));
        loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;82;0;I;INVENTOR;9;0"));
        loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;93;4;I;INVENTOR;5;0"));
        players.add(loser);

        Player loser2 = new Player("Loser2", TotemColor.PURPLE);
        loser2.addFood(2);
        loser2.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;54;2;I;SHAMAN;2;0"));
        loser2.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;36;2;I;BUILDER;3;1"));
        loser2.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;82;0;I;ARTIST;9;0"));
        loser2.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;93;4;I;INVENTOR;5;0"));
        players.add(loser2);
    }


    //Testing if solveEvents is able to execute a series of events
    @Test
    void solveEvents() {
        CardDeck cardDeck = new CardDeck();
        //cardDeck.setForNPlayerPath("./src/test/resources/files/only_event_deck.csv", 5);
        cardDeck.setForNPlayer(getClass().getResourceAsStream("/files/only_event_deck.csv"), 5);

        List<EventCard> events = new ArrayList<>();
        for(Card c: cardDeck.getTribeDeck()){
            events.add((EventCard) c);
        }

        assertTrue(EventsSolver.solveEvents(events, players));

    }

    //Testing if sustainment is giving the correct output after inserting a valid input

    @Test
    void sustainment() {
        EventCard sustainment = EventCard.parsRow("E;1;0;I;SUSTAINMENT;2;0");
        ArrayList<Integer> target = new ArrayList<>();
        target.add(players.getFirst().getFoodTokens());
        target.add(players.getFirst().getPrestigePoints());
        target.add(players.get(1).getFoodTokens() - 4);
        target.add(players.get(1).getPrestigePoints());
        target.add(0);
        target.add(players.get(3).getPrestigePoints()-8);
        target.add(0);
        target.add(players.get(3).getPrestigePoints()-8);
        assertEquals(target, EventsSolver.sustainment(sustainment, players));

    }

    //Testing if hunt is giving the correct output after inserting a valid input

    @Test
    void hunt() {
        EventCard hunt = EventCard.parsRow("E;1;0;I;HUNT;3;0");
        ArrayList<Integer> target = new ArrayList<>();
        target.add(players.getFirst().getFoodTokens() + 2);
        target.add(players.getFirst().getPrestigePoints() + 6);
        target.add(players.get(1).getFoodTokens() + 1);
        target.add(players.get(1).getPrestigePoints() + 3);
        target.add(players.get(2).getFoodTokens());
        target.add(players.get(2).getPrestigePoints());
        target.add(players.get(3).getFoodTokens());
        target.add(players.get(3).getPrestigePoints());
        assertEquals(target, EventsSolver.hunt(hunt, players));

    }

    //Testing if shamanicRitual is giving the correct output after inserting a valid input

    @Test
    void shamanicRitual() {
        EventCard shamanicRitual = EventCard.parsRow("E;1;0;I;SHAMANIC_RITUAL;10;5");

        ArrayList<Integer> target = new ArrayList<>();
        target.add(players.getFirst().getPrestigePoints() + 10);
        target.add(players.get(1).getPrestigePoints());
        target.add(players.get(2).getPrestigePoints()-5);
        target.add(players.get(3).getPrestigePoints()-5);
        assertEquals(target, EventsSolver.shamanicRitual(shamanicRitual, players));
    }

    //Testing if cavePainting is giving the correct output after inserting a valid input

    @Test
    void cavePaintings() {
        EventCard cavePainting = EventCard.parsRow("E;4;4;FINAL;CAVE_PAINTINGS;2;2");
        ArrayList<Integer> target = new ArrayList<>();
        target.add(players.getFirst().getPrestigePoints() + 6);
        target.add(players.get(1).getPrestigePoints() + 4);
        target.add(players.get(2).getPrestigePoints()-2);
        target.add(players.get(3).getPrestigePoints()-2);
        assertEquals(target, EventsSolver.cavePaintings(cavePainting, players));
    }

    @Test
    void wrongInputs(){
        EventCard cavePainting = EventCard.parsRow("E;4;4;FINAL;CAVE_PAINTINGS;2;2");

        Exception sustainmentException = assertThrows(EventsManagerException.class, () -> EventsSolver.sustainment(cavePainting, players));
        String SustainmentMessage = sustainmentException.getMessage();
        assertTrue(SustainmentMessage.contains("Not a sustainment card"));

        Exception shamanicException = assertThrows(EventsManagerException.class, () -> EventsSolver.shamanicRitual(cavePainting, players));
        String shamanicMessage = shamanicException.getMessage();
        assertTrue(shamanicMessage.contains("Not a shamanic ritual card"));

        Exception huntException = assertThrows(EventsManagerException.class, () -> EventsSolver.hunt(cavePainting, players));
        String huntMessage = huntException.getMessage();
        assertTrue(huntMessage.contains("Not a hunt card"));

        EventCard sustainment = EventCard.parsRow("E;1;0;I;SUSTAINMENT;2;0");

        Exception cavePaintingException = assertThrows(EventsManagerException.class, () -> EventsSolver.cavePaintings(sustainment, players));
        String cavePaintingMessage = cavePaintingException.getMessage();
        assertTrue(cavePaintingMessage.contains("Not a cave painting card"));

    }
}