package com.example.boidelov3.game;

import com.example.boidelov3.Question;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

/**
 * Moteur de jeu contenant toute la logique métier.
 * Indépendant de l'UI et du framework Android.
 */
public class GameEngine {
    private final Random random;
    private final List<Question> activeManches;

    public GameEngine() {
        this.random = new Random();
        this.activeManches = new ArrayList<>();
    }

    /**
     * Traite une question en remplaçant les variables.
     *
     * @param question La question à traiter
     * @param players La liste des joueurs
     * @param addedGorgees Nombre de gorgées additionnelles à ajouter
     * @return La question traitée avec les variables remplacées
     */
    public ProcessedQuestion processQuestion(Question question, List<String> players, int addedGorgees) {
        String questionText = question.getQuestion();
        boolean isManche = false;

        // Remplacer les variantes
        if (question.getVariante() != null && !question.getVariante().isEmpty()) {
            String chosenVariante = question.getVariante().get(random.nextInt(question.getVariante().size()));
            questionText = questionText.replace("<variante>", chosenVariante);
        }

        // Gérer les manches
        if (questionText.contains("<manches>")) {
            int manchesCount = random.nextInt(7) + 4;  // 4-10 manches
            questionText = questionText.replace("<manches>", String.valueOf(manchesCount));

            // Créer une copie de la question pour la manche active
            Question mancheQuestion = copyQuestion(question);
            mancheQuestion.setQuestion(questionText); // Question avec le nombre de manches
            mancheQuestion.setManchesRestantes(manchesCount);

            // Message de fin de manche
            String stopMessage = question.getArret() != null ? question.getArret() : "Fin du défi!";
            mancheQuestion.setArretMessageManche("Fin de défi!\n" + stopMessage);

            activeManches.add(mancheQuestion);
            isManche = true;
        }

        // Remplacer les joueurs et récupérer le nombre pour l'accord
        PlayerReplaceResult playerResult = replacePlayerPlaceholders(questionText, players);
        questionText = playerResult.questionText;

        // Ajouter les gorgées (en passant le nombre de joueurs pour l'accord)
        questionText = addGorgeesText(question, questionText, addedGorgees, playerResult.playerCount);

        // Mettre à jour la question avec le texte traité
        Question resultQuestion = isManche ? activeManches.get(activeManches.size() - 1) : copyQuestion(question);
        resultQuestion.setQuestion(questionText);

        return new ProcessedQuestion(resultQuestion, isManche);
    }

    /**
     * Résultat du remplacement des joueurs avec le nombre de joueurs
     */
    private static class PlayerReplaceResult {
        String questionText;
        int playerCount;

        PlayerReplaceResult(String questionText, int playerCount) {
            this.questionText = questionText;
            this.playerCount = playerCount;
        }
    }

    /**
     * Remplace les placeholders de joueurs dans la question et retourne le nombre de joueurs.
     */
    private PlayerReplaceResult replacePlayerPlaceholders(String questionText, List<String> players) {
        boolean hasJ1 = questionText.contains("<J1>");
        boolean hasJ2 = questionText.contains("<J2>");
        boolean hasJ3 = questionText.contains("<J3>");

        if (!hasJ1 && !hasJ2 && !hasJ3) {
            return new PlayerReplaceResult(questionText, 0);
        }

        List<String> selectedPlayers = selectRandomPlayers(players, 3);
        String result = questionText;
        int playerCount = 0;

        if (hasJ1 && hasJ2 && hasJ3 && selectedPlayers.size() >= 3) {
            playerCount = 3;
            result = result.replace("<J1>", selectedPlayers.get(0));
            result = result.replace("<J2>", selectedPlayers.get(1));
            result = result.replace("<J3>", selectedPlayers.get(2));
        } else if (hasJ1 && hasJ2 && selectedPlayers.size() >= 2) {
            playerCount = 2;
            result = result.replace("<J1>", selectedPlayers.get(0));
            result = result.replace("<J2>", selectedPlayers.get(1));
        } else if (hasJ1 && selectedPlayers.size() >= 1) {
            playerCount = 1;
            result = result.replace("<J1>", selectedPlayers.get(0));
        }

        return new PlayerReplaceResult(result, playerCount);
    }

    /**
     * Ajoute le texte des gorgées à la question.
     */
    private String addGorgeesText(Question question, String questionText, int addedGorgees, int playerCount) {
        if (!question.isDistribution() && !question.isRecois()) {
            return questionText;
        }

        StringBuilder sb = new StringBuilder(questionText);
        sb.append(" ");

        int totalGorgees = question.getGorger() + addedGorgees;

        // Accord du verbe selon le nombre de joueurs
        String boisVerb = (playerCount > 1) ? "boivent" : "boit";
        String distribueVerb = (playerCount > 1) ? "distribuent" : "distribue";

        // Déterminer si boire ou distribuer
        if (question.isRecois() && question.isDistribution()) {
            sb.append(random.nextBoolean() ? "<b>" + boisVerb + "</b>" : "<b>" + distribueVerb + "</b>");
        } else if (question.isRecois()) {
            sb.append("<b>" + boisVerb + "</b>");
        } else {
            sb.append("<b>" + distribueVerb + "</b>");
        }

        sb.append(" ").append(totalGorgees).append(" gorgée");
        if (totalGorgees > 1) {
            sb.append("s");
        }
        sb.append(".");

        return sb.toString();
    }

    /**
     * Sélectionne n joueurs aléatoires uniques.
     */
    public List<String> selectRandomPlayers(List<String> allPlayers, int count) {
        Set<String> selected = new HashSet<>();
        int available = Math.min(count, allPlayers.size());

        while (selected.size() < available) {
            selected.add(allPlayers.get(random.nextInt(allPlayers.size())));
        }

        return new ArrayList<>(selected);
    }

    /**
     * Met à jour les manches actives et retourne l'état.
     *
     * @return MancheState contenant la manche à afficher ou null si terminée
     */
    public MancheState updateManches() {
        if (activeManches.isEmpty()) {
            return new MancheState(null, false, null);
        }

        Question mancheQuestion = activeManches.get(0);
        mancheQuestion.setManchesRestantes(mancheQuestion.getManchesRestantes() - 1);

        if (mancheQuestion.getManchesRestantes() <= 0) {
            // Manche terminée
            String endMessage = mancheQuestion.getArretMessageManche();
            activeManches.remove(0);
            return new MancheState(null, false, endMessage);
        } else {
            // Manche toujours active
            return new MancheState(mancheQuestion, true, null);
        }
    }

    /**
     * @return true si une manche est active
     */
    public boolean hasActiveManche() {
        return !activeManches.isEmpty();
    }

    /**
     * @return le nombre de manches actives
     */
    public int getActiveManchesCount() {
        return activeManches.size();
    }

    /**
     * Vide toutes les manches actives.
     */
    public void clearManches() {
        activeManches.clear();
    }

    /**
     * Crée une copie d'une question (pour éviter de modifier l'original).
     */
    private Question copyQuestion(Question source) {
        Question copy = new Question();
        copy.setId(source.getId());
        copy.setQuestion(source.getQuestion());
        copy.setArret(source.getArret());
        copy.setVariante(source.getVariante());
        copy.setDistribution(source.isDistribution());
        copy.setRecois(source.isRecois());
        copy.setGorger(source.getGorger());
        copy.setManchesRestantes(source.getManchesRestantes());
        copy.setArretMessageManche(source.getArretMessageManche());
        return copy;
    }

    /**
     * Conteneur pour une question traitée.
     */
    public static class ProcessedQuestion {
        public final Question question;
        public final boolean isManche;

        public ProcessedQuestion(Question question, boolean isManche) {
            this.question = question;
            this.isManche = isManche;
        }
    }

    /**
     * État des manches après mise à jour.
     */
    public static class MancheState {
        public final Question activeManche;
        public final boolean hasManche;
        public final String endMessage;

        public MancheState(Question activeManche, boolean hasManche, String endMessage) {
            this.activeManche = activeManche;
            this.hasManche = hasManche;
            this.endMessage = endMessage;
        }
    }
}
