package it.polimi.ingsw.gc14.Model;

import it.polimi.ingsw.gc14.Model.Cards.BuildingCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Character;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.CharacterType;
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.platform.commons.annotation.Testable;

import java.util.*;

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

class GameTest {
    @Test void Game()
    {
        int nPlayers = 3;
        Game game=new Game(nPlayers);
        assertEquals(nPlayers,game.getNPlayers());
        assertEquals(GameStages.WAITING,game.getCurrentState().getGameStage());

        assertThrows(IllegalArgumentException.class,()->new Game(6));
        game=new Game();
        assertFalse(game.addPlayer(new Player("p1")));
        game.setNPlayer(nPlayers);
        assertTrue(game.addPlayer(new Player("p1")));
        assertEquals(nPlayers,game.getNPlayers());
        assertEquals(GameStages.WAITING,game.getCurrentState().getGameStage());
    }

    @Test
    void getUpperListTribeCards() {
        int nPlayers = 3;
        Game game=new Game(nPlayers);
        assertEquals(nPlayers+4 ,game.getUpperListTribeCards().size());
    }
    @Test
    void getUpperListBuildingCards() {
        int nPlayers = 3;
        Game game=new Game(nPlayers);
        assertEquals(2 ,game.getUpperListBuilding().size());
    }

    @Test
    void getLowerListBuildingCards() {
        int nPlayers = 3;
        Game game=new Game(nPlayers);
        assertEquals(0 ,game.getLowerListBuilding().size());
    }


    @Test
    void getLowerListTribeCards() {
        int nPlayers = 3;
        Game game=new Game(nPlayers);
        assertEquals(nPlayers+1 ,game.getLowerListTribeCards().size());
    }


    @Test
    void getPlayerByIndex() {
    }

    @Test
    void getNPlayers() {

    }

    @Test
    void addPlayer() {
        Game game=new Game(3);
        Player p1=new Player("p1");
        Player p2=new Player("p2");
        Player p3=new Player("p3");
        Player p4=new Player("p3");

        assertTrue(game.addPlayer(p1));
        assertTrue(game.addPlayer(p2));
        assertFalse(game.addPlayer(p2));
        assertTrue(game.addPlayer(p3));

        assertEquals(GameStages.SLOT_CHOICE,game.getCurrentState().getGameStage());
        assertFalse(game.addPlayer(p4));


    }

    @Test
    void init() {

    }

    @Test
    void slotChoiceByIndex() {
    }

    @Test
    void drawingByIndex() {
        Game game=new Game(3);
        Player p1=new Player("p1");
        Player p2=new Player("p2");
        Player p3=new Player("p3");
        Player p4=new Player("p3");

        assertTrue(game.addPlayer(p1));
        assertTrue(game.addPlayer(p2));
        assertFalse(game.addPlayer(p2));
        assertTrue(game.addPlayer(p3));

        Queue<Player>players=new LinkedList<>();
        for(int i=0;i<3;i++) {
            players.add( game.getCurrentState().getCurrentPlayer());
            assertTrue(game.SlotChoiceByIndex(game.getCurrentState().getCurrentPlayer(), i));
        }
        Player temp_player;

        temp_player=players.poll();
        assertEquals(temp_player,game.getCurrentState().getCurrentPlayer());

        int index;
        List<TribeCard> cards=game.getLowerListTribeCards();

        index=cards.indexOf(cards.stream().filter(x->!x.IsEventCard()).findFirst().get());
        assertTrue(game.DrawLowerTribeCardByIndex(temp_player,index));

        temp_player=players.poll();
        assertEquals(temp_player,game.getCurrentState().getCurrentPlayer());
        int nCards=game.getUpperListTribeCards().size();
        int countCards=0;
        HashMap<CharacterType,Integer>nCardsByType=new HashMap<CharacterType, Integer>();
        Arrays.stream(CharacterType.values()).forEach(type->nCardsByType.put(type,0));
        while(game.getCurrentState().getNUpper()>1) {
            cards=game.getUpperListTribeCards();
            TribeCard temp_card=cards.stream().filter(x->!x.IsEventCard()).findFirst().get();
            index=cards.indexOf(temp_card);
            assertEquals(nCards-countCards,game.getUpperListTribeCards().size()-countCards);
            drawTribeTest(nCardsByType,nCards,countCards,temp_card,temp_player,game);
            assertTrue(game.DrawUpperTribeCardByIndex(temp_player,index));
            countCards++;
        }
        cards=game.getUpperListTribeCards();

        index=cards.indexOf(cards.stream().filter(TribeCard::IsEventCard).findFirst().get());
        assertFalse(game.DrawUpperTribeCardByIndex(temp_player,index));
        //index=cards.indexOf(cards.stream().filter(x->!x.IsEventCard()).findFirst().get());
        //assertTrue(game.DrawUpperTribeCardByIndex(temp_player,index));
        List<BuildingCard> buildings=game.getUpperListBuilding();
        temp_player.addFood(10);
        index=0;
        assertTrue(game.DrawUpperBuildingCardByIndex(temp_player,index));
        index=cards.indexOf(cards.stream().filter(x->!x.IsEventCard()).findFirst().get());
        assertFalse(game.DrawUpperTribeCardByIndex(temp_player,index));


    }
    private void drawTribeTest(HashMap<CharacterType,Integer>nCardsByType,int nCards,int countCards,TribeCard temp_card,Player temp_player,Game game) {

        switch (((Character)temp_card).getType()) {
            case CharacterType.ARTIST:
                assertEquals( nCardsByType.get(((Character)temp_card).getType())+1,temp_player.artists.size());
                nCardsByType.merge(((Character)temp_card).getType(),1,Integer::sum);
                break;
            case CharacterType.INVENTOR:
                assertEquals( nCardsByType.get(((Character)temp_card).getType())+1,temp_player.inventors.size());
                nCardsByType.merge(((Character)temp_card).getType(),1,Integer::sum);
                break;
            case CharacterType.HUNTER:
                assertEquals( nCardsByType.get(((Character)temp_card).getType())+1,temp_player.hunters.size());
                nCardsByType.merge(((Character)temp_card).getType(),1,Integer::sum);
                break;
            case CharacterType.SHAMAN:
                assertEquals( nCardsByType.get(((Character)temp_card).getType())+1,temp_player.shamans.size());
                nCardsByType.merge(((Character)temp_card).getType(),1,Integer::sum);
                break;
            case CharacterType.BUILDER:
                assertEquals( nCardsByType.get(((Character)temp_card).getType())+1,temp_player.builders.size());
                nCardsByType.merge(((Character)temp_card).getType(),1,Integer::sum);
                break;
            case CharacterType.GATHERER:
                assertEquals( nCardsByType.get(((Character)temp_card).getType())+1,temp_player.gatherers.size());
                nCardsByType.merge(((Character)temp_card).getType(),1,Integer::sum);
                break;

        }
    }

    @Test
    void pickOptionalTribeCard() {
    }
    @Test
    void pickOptionalBuildingCard() {
    }
    @Test
    void noOptionalCard() {
    }
}