package Server;

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

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



public class Tribe {
    // Attributes
    private List<CharacterCard> characters;
    private List<BuildingCard> buildings;

    // Constructor
    public Tribe() {
        this.characters = new ArrayList<>();
        this.buildings = new ArrayList<>();
    }

    public List<CharacterCard> getCharacters() {
        return characters;
    }
    public List<BuildingCard> getBuildingCard() {
        return buildings;
    }
    // METODI


    public int addCharacter(CharacterCard card) {
        this.characters.add(card);
        if (card.getCharacterType().equals(CharacterType.HUNTER)) {
            return hunterGetFood(card);
        }
        return 0;
    }

    // Metodo per aggiungere un nuovo building alla tribù
    public void addBuilding(BuildingCard card) {
        this.buildings.add(card);
    }

    // Metodo per ottenere lo sconto in cibo in base a quanti gatherer abbiamo nella tribù
    public int gathererDiscount() {
        int discount = 0;
        for (CharacterCard c : characters) {
            if (c.getCharacterType() == CharacterType.GATHERER) {
                discount += 3; // i gatherers prendono sempre 3 cibi
            }
        }
        return discount;
    }

    // Metodo per ottenere lo sconto totale sugli edifici grazie ai builder nella tribù
    public int buildersDiscount() {
        int discount = 0;
        for (CharacterCard c : characters) {
            if (c.getCharacterType() == CharacterType.BUILDER) {
                discount += c.getIconValue(); // con getIconValue intendo lo sconto del costruttore
            }
        }
        return discount;
    }

    // Metodo che conta quante stelle degli sciamani abbiamo in totale nella tribù
    public int shamansIcons() {
        int totalIcons = 0;
        for (CharacterCard c : characters) {
            if (c.getCharacterType() == CharacterType.SHAMAN) {
                totalIcons += c.getIconValue();
            }
        }
        return totalIcons;
    }

    // Metodo che restituisce il numero di artisti nella tribù
    public int artistsNumber() {
        return countCharactersByType(CharacterType.ARTIST);
    }

    // Metodo che restituisce il numero di cacciatori nella tribù
    public int huntersNumber() {
        return countCharactersByType(CharacterType.HUNTER);
    }

    // Metodo universale per contare le carte di un certo tipo all'interno della tribù
    public int countCharactersByType(CharacterType typeToCount) {
        int count = 0;
        for (CharacterCard c : characters) {
            if (c.getCharacterType() == typeToCount) {
                count++;
            }
        }
        return count;
    }

    // Metodo che ritorna il numero totale di cibi ottenuti dopo aver pescato il cacciatore col cosciotto
    public int hunterGetFood(CharacterCard hunter) {
        return huntersNumber() * hunter.getIconValue(); // getIconValue = 1 se il cacciatore ha il cosciotto
    }

    // Metodo che restituisce i punti finali degli inventori
    public int inventorsEndPoints() {
        int inventorCount = 0;
        List<Integer> uniqueInventions = new ArrayList<>();

        for (CharacterCard c : characters) {
            if (c.getCharacterType() == CharacterType.INVENTOR) {
                inventorCount++;

                int inventionId = c.getIconValue(); // Usiamo l'iconValue del file cards.csv

                // Se non abbiamo ancora contato questa invenzione, la aggiungiamo
                if (!uniqueInventions.contains(inventionId)) {
                    uniqueInventions.add(inventionId);
                }
            }
        }
        return inventorCount * uniqueInventions.size();
    }

    // Metodo che restituisce i punti finali degli artisti
    public int artistsEndPoints() {
        return (artistsNumber() / 2) * 10; // in java 1/2 fa 0
    }

    // Metodo che restituisce i punti finali dei costruttori
    public int buildersEndPoints() {
        int points = 0;
        for (CharacterCard c : characters) {
            if (c.getCharacterType() == CharacterType.BUILDER) {
                points += c.getPrestigePoints();
            }
        }
        return points;
    }

    // Metodo che restituisce i punti finali guadagnati grazie agli EFFETTI delle carte building
    private int buildingAbilitiesEndPoints() {
        int bonusPoints = 0;

        for (BuildingCard b : buildings) {
            Trigger trigger = b.getAbilityTrigger(); // leggiamo il trigger della carta edificio

            // Se la carta per qualche motivo non ha trigger, passiamo alla prossima
            if (trigger == null) {
                continue;
            }

            switch (trigger) {
                case ENDGAME_BUILDER_BONUS: // id carta: 107
                    bonusPoints += (buildersEndPoints() * 2);
                    break;

                case ENDGAME_FOR_SIX: // id carta: 109
                    // Prepariamo i contatori per tutti e 6 i tipi di characters
                    int inv = 0, hun = 0, gat = 0, sha = 0, art = 0, bui = 0;

                    // contiamo le carte nella tribù
                    for (CharacterCard c : characters) {
                        switch (c.getCharacterType()) {
                            case INVENTOR: inv++; break;
                            case HUNTER:   hun++; break;
                            case GATHERER: gat++; break;
                            case SHAMAN:   sha++; break;
                            case ARTIST:   art++; break;
                            case BUILDER:  bui++; break;
                        }
                    }

                    // troviamo il numero di set completi
                    int min1 = Math.min(inv, hun);
                    int min2 = Math.min(gat, sha);
                    int min3 = Math.min(art, bui);
                    int completeSets = Math.min(Math.min(min1, min2), min3);

                    // aggiungiamo 6 punti prestigio per ogni set completo
                    bonusPoints += (completeSets * 6);
                    break;

                case ENDGAME_BONUS_CHARACTER:

                    int id = b.getCardId(); // uso l'id della carta per capire che edificio è

                    // il numero id corrisponde al numero di pagina nel pdf
                    if (id == 110) { // edificio dei cacciatori
                        bonusPoints += countCharactersByType(CharacterType.HUNTER) * 3;
                    }
                    else if (id == 111) { // edificio dei gatherer
                        bonusPoints += countCharactersByType(CharacterType.GATHERER) * 4;
                    }
                    else if (id == 112) { // edificio degli sciamani
                        bonusPoints += countCharactersByType(CharacterType.SHAMAN) * 4;
                    }
                    else if (id == 113) { // edificio dei costruttori
                        bonusPoints += countCharactersByType(CharacterType.BUILDER) * 4;
                    }
                    else if (id == 114) { // edificio degli artisti
                        bonusPoints += countCharactersByType(CharacterType.ARTIST) * 4;
                    }
                    else if (id == 115) { // edificio degli inventori
                        bonusPoints += countCharactersByType(CharacterType.INVENTOR) * 2;
                    }
                    break;

                case ENDGAME_BONUS_POINTS: // id carta: 117
                    bonusPoints += 25; // dà 25 punti bonus
                    break;

                default:
                    break;
            }
        }
        return bonusPoints;
    }

    // Metodo che calcola i punti finali totali
    public int endPoints() {
        int total = 0;

        // sommiamo i punti calcolati dai vari personaggi
        total += inventorsEndPoints();
        total += artistsEndPoints();
        total += buildersEndPoints();

        // sommiamo i punti prestigio BASE di tutti gli edifici (EndPP)
        for (BuildingCard b : buildings) {
            total += b.getEndPP();
        }

        // sommiamo gli effetti degli edifici sul punteggio finale, NON quelli durante la partita
        total += buildingAbilitiesEndPoints();

        return total;
    }
}
