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.EventCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.EventType;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Events.ShamanicRitual;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Events.Sustenance;
import it.polimi.ingsw.gc14.Model.GamePackage.CurrentState;
import it.polimi.ingsw.gc14.Model.Orders.Order2;
import it.polimi.ingsw.gc14.Model.Orders.Order3;
import it.polimi.ingsw.gc14.Model.Orders.Order4;
import it.polimi.ingsw.gc14.Model.Orders.Order5;
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
import javafx.event.Event;

import java.util.*;
import java.util.stream.Collectors;

public class Game {
    private List<Slot> slotList;

    private Queue<TribeCard> tribeDeck;
    private List<TribeCard> upperListTribe;
    private List<TribeCard> lowerListTribe;
    private List<BuildingCard> upperListBuilding;
    private List<BuildingCard> lowerListBuilding;
    private ArrayList<Player> playersList;

    private CurrentState currentState;
    private HashMap<Slot,Player> slotMap ;
    private int nPlayers;
    private OrderLogicCard orderLogicCard;

    public Game(int nPlayers) {
        this.nPlayers = nPlayers;
        this.slotList = DecksCreator.loadSlotDeck().stream().filter(x->x.getNMinPlayer()<=nPlayers).sorted().toList();
            slotMap = new LinkedHashMap<>();
        for(Slot s :DecksCreator.loadSlotDeck().stream().filter(x->x.getNMinPlayer()<=nPlayers).sorted().toList())
        {
            slotMap.put(s,null);
        }

        this.tribeDeck= getTribeDeck(nPlayers);
        ArrayList<BuildingCard> buildingDeck = new ArrayList<>(DecksCreator.loadBuildingDeckByEra(1));
        Collections.shuffle(buildingDeck);
        if(nPlayers==2)
            this.upperListBuilding= buildingDeck.subList(0,1);
        else
            this.upperListBuilding= buildingDeck.subList(0,2);
        currentState= new CurrentState();
        upperListTribe = new ArrayList<>();
        lowerListTribe = new ArrayList<>();
        lowerListBuilding = new ArrayList<>();
        playersList = new ArrayList<>();
    }
    public void init()
    {
        switch (nPlayers) {
            case 2:
                orderLogicCard=new Order2(playersList);
                break;
            case 3:
                orderLogicCard=new Order3(playersList);
                break;
            case 4:
                orderLogicCard=new Order4(playersList);
                break;
            case 5:
                orderLogicCard=new Order5(playersList);
                break;
        }

        for(int i=0;i<nPlayers+1;i++)
        {
            TribeCard tempCard = tribeDeck.remove();
            if(tempCard.IsEventCard())
            {
                upperListTribe.add(tempCard);
                i--;
            }
            else
            {
                lowerListTribe.add(tempCard);
            }
        }
        for(int i=upperListTribe.size();i<nPlayers+5;i++)
        {
            TribeCard tempCard = tribeDeck.remove();
            upperListTribe.add(tempCard);
        }
        currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
        currentState.PlayerUpdate(orderLogicCard.pull(),null);
    }
    public boolean SlotChoice(Player player, Slot slot)
    {
        if(currentState.getGameStage()!= GameStages.SLOT_CHOICE)
        {
            return false;
        }
        if(player.equals(currentState.getCurrentPlayer()))
        {
            if(slotMap.get(slot)!=null)
            {
                return false;
            }
            if(!slotList.contains(slot))
            {
                return false;
            }
            slotMap.put(slot,player);
            currentState.PlayerUpdate(orderLogicCard.pull(),null);
            if(currentState.getCurrentPlayer()==null)
            {
                currentState.GameStageUpdate(GameStages.RESOLVING_ACTIONS);
                for(Slot s : slotList)
                {
                    if(slotMap.get(s)!=null)
                    {
                        currentState.PlayerUpdate(slotMap.get(s),s);
                    }
                }
            }
            return true;
        }
        return false;
    }


    public boolean DrawTribeCard(Player player,TribeCard tribeCard)
    {
        if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
        {
            return false;
        }
        if(player.equals(currentPlayer))
        {

        }
        return false;

    }
    public boolean DrawUpperBuildingCard(Player player,BuildingCard buildingCard)
    {
        if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
        {
            return false;
        }
        if(!player.equals(currentState.getCurrentPlayer()))
        {
            return false;
        }
        if(!upperListBuilding.contains(buildingCard))
        {
            return false;
        }
        if(buildingCard.buy(player))
            currentState.UpperDrawn();
        else
            return false;
        if(currentState.getNUpper()==currentState.getSlot().getNUpper()&& currentState.getNLower()==currentState.getSlot().getNLower())
        {

        }
        return false;
    }

    private void nextPlayerSetup()
    {
        if(GameStages.RESOLVING_ACTIONS==currentState.getGameStage()) {
            orderLogicCard.push(currentState.getCurrentPlayer());
            slotMap.put(currentState.getSlot(), null);
            for (Slot s : slotList) {
                if (slotMap.get(s) != null) {
                    currentState.PlayerUpdate(slotMap.get(s), s);
                }
            }
            if(slotMap.values().stream().allMatch(v -> v == null))
            {
                currentState.GameStageUpdate(GameStages.BUILDING_EFFECT_12);
                BuildingEffect12( playersList.stream().filter(x->x.buildingCards.stream().anyMatch(y->y.getEffectId()==12)).toList());
                //currentState.PlayerUpdate(orderLogicCard.pull(),null);

            }
        }
    }
    private void BuildingEffect12(List<Player> playerList)
    {

    }
    private void EventResolution()
    {

        if(currentState.getGameStage()!= GameStages.RESOLVING_EVENT)
        {
            return;
        }
        Queue<EventCard> events;
        events=lowerListTribe.stream().filter(TribeCard::IsEventCard).map(x->(EventCard)x).collect(Collectors.toCollection(LinkedList::new));


        ArrayList<EventCard>sustenance=events.stream().filter(x->x.getType().equals(EventType.SUSTENANCE)).collect(Collectors.toCollection(ArrayList::new));
        events.removeAll(sustenance);
        for(EventCard event:events)
        {
            event.activateEvent(playersList);
        }

        for(EventCard e : sustenance)
        {
            e.activateEvent(playersList);
        }


    }
    private void nextRound()
    {

        EventResolution();

    }
    private Queue<TribeCard>  getTribeDeck(int nPlayers)
    {
        ArrayList<TribeCard> era1= DecksCreator.loadTribeDeckByEra(1).stream().filter(x->x.getNMin()<=nPlayers).collect(Collectors.toCollection(ArrayList::new));
        List<TribeCard> era2= DecksCreator.loadTribeDeckByEra(2).stream().filter(x->x.getNMin()<=nPlayers).collect(Collectors.toCollection(ArrayList::new));
        List<TribeCard> era3= DecksCreator.loadTribeDeckByEra(3).stream().filter(x->x.getNMin()<=nPlayers).collect(Collectors.toCollection(ArrayList::new));
        Collections.shuffle(era1);
        Collections.shuffle(era2);
        Collections.shuffle(era3);
        Queue<TribeCard> tribeDeck_temp=new LinkedList<>();
        tribeDeck_temp.addAll(era1);
        tribeDeck_temp.addAll(era2);
        tribeDeck_temp.addAll(era3);
        tribeDeck_temp.add(new Sustenance(3,3));
        tribeDeck_temp.add(new ShamanicRitual(3,15,7));
        return tribeDeck_temp;
    }

    public boolean addPlayer(Player player)
    {
        if(currentState.getGameStage()!= GameStages.WAITING)
            return false;
        playersList.add(player);

        if(playersList.size()>=nPlayers)
        {
            init();
            return true;
        }
        return false;
    }







}
