package com.example.boidelov3.games.papelito;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

/**
 * Logique du jeu Papelito (Undercover)
 */
public class PapelitoGame {

    private final List<PapelitoPlayer> players;
    private final List<PapelitoPlayer> alivePlayers;
    private final List<String> wordPairs;
    private String currentCivilWord;
    private String currentUndercoverWord;
    private int currentPlayerIndex;
    private final Random random;
    private GameState gameState;

    public enum GameState {
        SETUP,
        DISCUSSION,
        VOTING,
        RESULT,
        GAME_OVER
    }

    // Paires de mots pour le jeu (civil / undercover)
    private static final String[][] DEFAULT_WORD_PAIRS = {
        {"Pizza", "Burger"},
        {"Facebook", "Instagram"},
        {"Chat", "Chien"},
        {"Foot", "Basket"},
        {"Vin", "Bière"},
        {"Mer", "Montagne"},
        {"Avion", "Hélicoptère"},
        {"Piano", "Guitare"},
        {"Fromage", "Dessert"},
        {"École", "Fac"},
        {"Mariage", "Divorce"},
        {"Hôpital", "Cabinet"},
        {"Boulangerie", "Boucherie"},
        {"Zombie", "Vampire"},
        {"Pirate", "Ninja"},
        {"Cowboy", "Indien"},
        {"Fée", "Sorcière"},
        {"Robot", "Alien"},
        {"Dragon", "Licorne"}
    };

    public PapelitoGame() {
        this.players = new ArrayList<>();
        this.alivePlayers = new ArrayList<>();
        this.wordPairs = new ArrayList<>();
        this.random = new Random();
        this.gameState = GameState.SETUP;

        // Ajouter les paires de mots par défaut
        for (String[] pair : DEFAULT_WORD_PAIRS) {
            wordPairs.add(pair[0] + "|" + pair[1]);
        }
    }

    /**
     * Configure une nouvelle partie
     */
    public void setupGame(List<String> playerNames, int undercoverCount) {
        players.clear();

        // Créer les joueurs
        for (String name : playerNames) {
            players.add(new PapelitoPlayer(name));
        }

        // Vérifier qu'on a assez de joueurs
        if (undercoverCount >= players.size()) {
            throw new IllegalArgumentException("Il faut plus de joueurs que d'undercovers");
        }

        // Choisir une paire de mots aléatoire
        String[] words = selectRandomWordPair();
        currentCivilWord = words[0];
        currentUndercoverWord = words[1];

        // Assigner les rôles
        assignRoles(undercoverCount);

        // Initialiser la liste des joueurs vivants
        alivePlayers.clear();
        alivePlayers.addAll(players);

        gameState = GameState.DISCUSSION;
    }

    /**
     * Sélectionne une paire de mots aléatoire
     */
    private String[] selectRandomWordPair() {
        String pair = wordPairs.get(random.nextInt(wordPairs.size()));
        String[] words = pair.split("\\|");
        if (words.length != 2) {
            throw new IllegalStateException("Invalid word pair format: " + pair);
        }
        return words;
    }

    /**
     * Assigne les rôles aux joueurs
     */
    private void assignRoles(int undercoverCount) {
        if (players.isEmpty()) return;

        // Mélanger les joueurs
        List<PapelitoPlayer> shuffled = new ArrayList<>(players);
        Collections.shuffle(shuffled);

        // Assigner les undercovers
        for (int i = 0; i < undercoverCount; i++) {
            shuffled.get(i).setRole(PapelitoPlayer.Role.UNDERCOVER);
            shuffled.get(i).setSecretWord(currentUndercoverWord);
        }

        // Le reste sont des civils
        for (int i = undercoverCount; i < shuffled.size(); i++) {
            shuffled.get(i).setRole(PapelitoPlayer.Role.CIVIL);
            shuffled.get(i).setSecretWord(currentCivilWord);
        }
    }

    /**
     * Enregistre un vote contre un joueur
     */
    public boolean vote(PapelitoPlayer voter, PapelitoPlayer votedPlayer) {
        if (!voter.isAlive() || !votedPlayer.isAlive()) {
            return false;
        }

        if (!gameState.equals(GameState.VOTING)) {
            return false;
        }

        // Vérifier que le joueur n'a pas déjà voté
        // (pour simplifier, on ne track pas qui a voté, chaque joueur peut voter une fois)

        votedPlayer.addVote();
        return true;
    }

    /**
     * Élimine le joueur avec le plus de votes
     * Retourne null si pas de votes ou en cas d'égalité
     */
    public PapelitoPlayer eliminateMostVoted() {
        if (alivePlayers.isEmpty()) {
            return null;
        }

        PapelitoPlayer mostVoted = null;
        int maxVotes = -1;
        int playersWithMaxVotes = 0;

        // Trouver le nombre maximum de votes
        for (PapelitoPlayer player : alivePlayers) {
            if (player.getVotesReceived() > maxVotes) {
                maxVotes = player.getVotesReceived();
                mostVoted = player;
                playersWithMaxVotes = 1;
            } else if (player.getVotesReceived() == maxVotes && maxVotes > 0) {
                // Égalité détectée
                playersWithMaxVotes++;
            }
        }

        // Si pas de votes ou égalité entre plusieurs joueurs, personne n'est éliminé
        if (maxVotes <= 0 || playersWithMaxVotes > 1) {
            return null;
        }

        if (mostVoted != null) {
            mostVoted.eliminate();
            alivePlayers.remove(mostVoted);

            // Révéler son rôle
            return mostVoted;
        }

        return null;
    }

    /**
     * Vérifie si la partie est terminée
     */
    public boolean checkGameOver() {
        int civilsCount = 0;
        int undercoversCount = 0;

        for (PapelitoPlayer player : alivePlayers) {
            if (player.isCivil()) {
                civilsCount++;
            } else if (player.isUndercover()) {
                undercoversCount++;
            }
        }

        // Les civils gagnent s'il n'y a plus d'undercovers
        if (undercoversCount == 0) {
            gameState = GameState.GAME_OVER;
            return true;
        }

        // Les undercovers gagnent s'ils sont en nombre égal ou supérieur aux civils
        // Explication: Si les undercovers sont égal ou plus nombreux, les civils ne peuvent plus gagner
        // car il n'y aurait plus assez de civils pour voter et éliminer tous les undercovers
        if (undercoversCount >= civilsCount) {
            gameState = GameState.GAME_OVER;
            return true;
        }

        return false;
    }

    /**
     * Obtient le joueur actuel
     */
    public PapelitoPlayer getCurrentPlayer() {
        if (!alivePlayers.isEmpty()) {
            // Utilise alivePlayers pour les joueurs vivants
            if (currentPlayerIndex >= 0 && currentPlayerIndex < alivePlayers.size()) {
                return alivePlayers.get(currentPlayerIndex);
            }
        }
        return null;
    }

    /**
     * Passe au joueur suivant
     */
    public void nextPlayer() {
        if (!alivePlayers.isEmpty()) {
            currentPlayerIndex = (currentPlayerIndex + 1) % alivePlayers.size();
        }
    }

    /**
     * Obtient le nombre de civils vivants
     */
    public int getAliveCivilsCount() {
        int count = 0;
        for (PapelitoPlayer player : alivePlayers) {
            if (player.isCivil()) {
                count++;
            }
        }
        return count;
    }

    /**
     * Obtient le nombre d'undercovers vivants
     */
    public int getAliveUndercoversCount() {
        int count = 0;
        for (PapelitoPlayer player : alivePlayers) {
            if (player.isUndercover()) {
                count++;
            }
        }
        return count;
    }

    /**
     * Obtient les gagnants
     */
    public PapelitoPlayer.Role getWinningTeam() {
        int civilsCount = getAliveCivilsCount();
        int undercoversCount = getAliveUndercoversCount();

        if (undercoversCount == 0) {
            return PapelitoPlayer.Role.CIVIL;
        } else if (undercoversCount >= civilsCount) {
            return PapelitoPlayer.Role.UNDERCOVER;
        }

        return null;
    }

    /**
     * Réinitialise les votes pour un nouveau tour
     */
    public void resetVotes() {
        for (PapelitoPlayer player : players) {
            player.resetVotes();
        }
    }

    // Getters
    public List<PapelitoPlayer> getPlayers() {
        return new ArrayList<>(players);
    }

    public List<PapelitoPlayer> getAlivePlayers() {
        return new ArrayList<>(alivePlayers);
    }

    public String getCurrentCivilWord() {
        return currentCivilWord;
    }

    public String getCurrentUndercoverWord() {
        return currentUndercoverWord;
    }

    public GameState getGameState() {
        return gameState;
    }

    public void setGameState(GameState state) {
        // Validation des transitions légales entre états
        GameState current = this.gameState;

        // Transitions légales autorisées
        if (current == GameState.SETUP && state != GameState.DISCUSSION && state != GameState.SETUP) {
            throw new IllegalStateException("Cannot transition from SETUP to " + state);
        }
        if (current == GameState.DISCUSSION && state != GameState.VOTING && state != GameState.SETUP) {
            throw new IllegalStateException("Cannot transition from DISCUSSION to " + state);
        }
        if (current == GameState.VOTING && state != GameState.RESULT && state != GameState.SETUP) {
            throw new IllegalStateException("Cannot transition from VOTING to " + state);
        }
        if (current == GameState.RESULT && state != GameState.DISCUSSION && state != GameState.GAME_OVER && state != GameState.SETUP) {
            throw new IllegalStateException("Cannot transition from RESULT to " + state);
        }
        if (current == GameState.GAME_OVER && state != GameState.SETUP) {
            throw new IllegalStateException("Cannot transition from GAME_OVER to " + state);
        }

        this.gameState = state;
    }

    public void reset() {
        players.clear();
        alivePlayers.clear();
        currentPlayerIndex = 0;
        gameState = GameState.SETUP;
    }
}
