package Server;

import Server.Cards.BuildingCard;
import Server.Cards.CharacterCard;
import Server.Cards.CharacterType;
import Server.Cards.Trigger;
import Server.Utils.EventsManagerException;


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

public class BuildingManager {
    private static List<BuildingCard> activeBuildings;

    public BuildingManager() {
        activeBuildings = new ArrayList<>();
    }

    public void addActiveBuilding (BuildingCard buildingCard, Player player) {
        buildingCard.setOwner(player);
        activeBuildings.add(buildingCard);
    }

    public static BuildingCard playerHasBuilding(Player player, Trigger trigger) {

        for (BuildingCard buildingCard : activeBuildings) {
            if(buildingCard.getAbilityTrigger() == trigger && buildingCard.getOwner() == player) {
                return buildingCard;
            }
        }
        return null;
    }

    public static int numberOfTargets(Player player, List<BuildingCard> buildingCards) {
        int numCard = 0;
        for (BuildingCard buildingCard : buildingCards) {

            List<CharacterCard> playerCharacters = player.getPlayerTribe().getCharacters();

            for (CharacterCard card : playerCharacters) {
                if (card.getCharacterType() == buildingCard.getEffectTarget()) {
                    numCard++;
                }
            }
        }
        return numCard;
    }

    public static List<BuildingCard> playerHasVariousBuildings(Player player, Trigger trigger) {

        List<BuildingCard> buildingCards = new ArrayList<>();

        for (BuildingCard buildingCard : activeBuildings) {
            if(buildingCard.getAbilityTrigger() == trigger && buildingCard.getOwner() == player) {
                buildingCards.add(buildingCard);
            }
        }
        return buildingCards;
    }

    //When a player draw a characterCard, if said card complete a set of 6
    //different character type, give the player 6 food

    public static void foodForSix(Player player, CharacterCard characterCard) {
        if(playerHasBuilding(player, Trigger.FOOD_FOR_SIX) == null){
            return;
        }

        List<CharacterCard> playerTribe = player.getPlayerTribe().getCharacters();
        int [] preDraw = new int[CharacterType.values().length];
        int [] postDraw = new int[CharacterType.values().length];

        for(CharacterCard card: playerTribe){
            preDraw[card.getCharacterType().ordinal()]++;
            postDraw[card.getCharacterType().ordinal()]++;
        }

        postDraw[characterCard.getCharacterType().ordinal()]++;

        int minPre = Arrays.stream(preDraw).min().getAsInt();
        int minPost = Arrays.stream(postDraw).min().getAsInt();

        if(minPre < minPost){
            player.addFood(6);
        }

    }

    //the method return the discount received for the player based on the cards he owns
    //the card providing the discount are indicated on the BuildingCard
    public static int sustainDiscount(Player player) {
        List<BuildingCard> buildingCards = playerHasVariousBuildings(player, Trigger.SUSTAIN_DISCOUNT);
        if(buildingCards.isEmpty()){
            return 0;
        }
        return numberOfTargets(player, buildingCards);
    }

    //if the player is going to lose during the shamanicRitual, the loss are nullif
    public static boolean shamanNoLoss(Player player) {
        return playerHasBuilding(player, Trigger.SHAMAN_NO_LOSS) != null;
    }

    //check if the player has a SHAMAN_DOUBLE_POINTS card
    public static boolean shamanDoublePoints(Player player) {
        return playerHasBuilding(player, Trigger.SHAMAN_DOUBLE_POINTS) != null;
    }

    //if the player has a BONUS_END_TURN buildingCard the player gain additional food
    //after placing his totem on a tile whit food
    public static int bonusEndTurn(Player player, int positionReward) {
        if (playerHasBuilding(player, Trigger.BONUS_FOOD_ENDTURN) == null) return -1;

        if (positionReward >= 1){
            player.addFood(1);
            return 1;
        }

        return 0;
    }

    //if the player has a BuildingCard whit FOOD_PER_INVENTORS, and he
    //draws a copy of an inventor that is already in his tribe he gains 3 food
    public static void foodPerInventors(Player player, CharacterCard characterCard) {
        if(playerHasBuilding(player, Trigger.FOOD_PER_INVENTORS) == null){
            return;
        }

        if(characterCard.getCharacterType()!= CharacterType.INVENTOR){
            throw new EventsManagerException("Invalid character type");
        }

        List<CharacterCard> playerTribe = player.getPlayerTribe().getCharacters();
        int numberOfInventors = 0;

        for(CharacterCard card: playerTribe){
            if(card.getIconValue() == characterCard.getIconValue() && card.getCharacterType() == CharacterType.INVENTOR){
                numberOfInventors++;
            }
        }

        if(numberOfInventors%2 == 1)
            player.addFood(3);
    }

    //if the player has a SHAMAN_BONUS building the function return 3, else return 0
    public static int shamanBonus(Player player) {
        if (BuildingManager.playerHasBuilding(player, Trigger.SHAMAN_BONUS) == null) return 0;
        return 3;
    }

    //return if HUNT_BONUS is active for the player
    public static boolean hunterBonus(Player player) {
        return playerHasBuilding(player, Trigger.HUNT_BONUS) != null;
    }

    //return if ENDGAME_BUILDER_BONUS is active for the player
    public static boolean endgameBuilderBonus(Player player) {
        return playerHasBuilding(player, Trigger.ENDGAME_BUILDER_BONUS) != null;
    }

    //return the amount of food gained if the player has a BuildingCard with
    //PAINTING_FOOD_BONUS, a unit for each ARTIST in his tribe
    public static void paintingFoodBonus(Player player) {
        if(playerHasBuilding(player, Trigger.PAINTING_FOOD_BONUS) == null) return;

        player.addFood(player.getPlayerTribe().artistsNumber());
    }

    //return the amount of buildingPoint if the player has a BuildingCard with
    //ENDGAME_FOR_SIX, a unit for each set of 6 character of different Type
    public static void endgameForSix(Player player) {
        if(playerHasBuilding(player, Trigger.ENDGAME_FOR_SIX) == null) return;

        List<CharacterCard> playerTribe = player.getPlayerTribe().getCharacters();

        int [] typeDuplicates = new int[CharacterType.values().length];

        for(CharacterCard card: playerTribe){
            typeDuplicates[card.getCharacterType().ordinal()]++;
        }

        int minCharacterType = Arrays.stream(typeDuplicates).min().getAsInt();

        player.addPrestigePoints(minCharacterType*6);
    }

    //add the bonus prestigePoints due to ENDGAME_BONUS_CHARACTER, the amount is based
    //on the CharacterType indicated on the BuildingCards, 3 for each character of the same type
    //A plater can own different BuildingCards with the same effect
    public static void endgameBonusCharacter(Player player) {
        List<BuildingCard> buildingCards = playerHasVariousBuildings(player, Trigger.ENDGAME_BONUS_CHARACTER);
        if(buildingCards.isEmpty()){
            return;
        }

        player.addPrestigePoints(numberOfTargets(player, buildingCards)* 3);
    }

    //return if EXTRA_DRAW is active for the player
    public static boolean extraDraw(Player player) {
        return playerHasBuilding(player, Trigger.EXTRA_DRAW) != null;
    }

    //return if the player has a BuildingCard with
    //ENDGAME_BONUS_POINTS, then add 25 points if he has
    public static void endgameBonusPoints(Player player) {
        if(playerHasBuilding(player, Trigger.ENDGAME_BONUS_POINTS) == null) return;

        player.addPrestigePoints(25);
    }
}
