using CoreLibrary.Exceptions;

namespace CoreLibrary
{
    /// <summary>
    /// Implémente les règles du jeu.
    /// </summary>
    public class ReglesClassiques : IRegles
    {
        private int nbJoueurs = 0;
        private int? joueurCourant;
        private readonly Joueur[] joueurs;

        /// <summary>
        /// Obtient le nom des règles.
        /// </summary>
        public string Nom { get => "Règles classiques"; }

        /// <summary>
        /// Obtient le nombre maximum de tours.
        /// </summary>
        public int TourMaximum { get => 12; }

        /// <summary>
        /// Obtient la taille maximale d'un code.
        /// </summary>
        public int TailleCodeMaximum { get => 4; }
        /// <summary>
        /// Obtient le nombre de joueurs actuels dans le jeu.
        /// </summary>
        public int NbJoueurs { get => nbJoueurs; }
        /// <summary>
        /// Obtient le nombre maximum de joueurs possible pour le jeu.
        /// </summary>
        public int NbJoueursMaximum { get => 2; }


        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="ReglesClassiques"/> en initialisant un tableau de joueurs avec la taille maximale de joueurs autorisée.
        /// </summary>
        public ReglesClassiques()
        {
            joueurs = new Joueur[NbJoueursMaximum];
        }



        /// <summary>
        /// Ajoute un joueur avec le nom spécifié.
        /// </summary>
        /// <param name="nom">Le nom du joueur à ajouter.</param>
        /// <returns>Le joueur ajouté.</returns>
        public Joueur AjouterJoueur(string nom)
        {
            Joueur joueur = new Joueur(nom, new Plateau(TailleCodeMaximum, TourMaximum));
            joueurs[nbJoueurs++] = joueur;
            return joueur;
        }

        /// <summary>
        /// Obtient le joueur dont c'est actuellement le tour.
        /// </summary>
        /// <returns>Le joueur actuel.</returns>
        /// <exception cref="PartieNonCommenceeException">Levée lorsqu'il n'y a pas de joueur courant.</exception>

        public Joueur JoueurCourant()
        {
            if (!joueurCourant.HasValue)
                throw new PartieNonCommenceeException();

            return joueurs[joueurCourant.Value];
        }

        /// <summary>
        /// Passe la main au joueur suivant.
        /// </summary>
        /// <exception cref="PartieNonCommenceeException">Levée lorsqu'il n'y a pas de joueur courant.</exception>
        public void PasserLaMain()
        {
            if (!joueurCourant.HasValue)
            {
                throw new PartieNonCommenceeException();
            }

            joueurCourant++;
            if (joueurCourant >= joueurs.Length)
            {
                joueurCourant = 0;
            }

        }

        /// <summary>
        /// Génère un nouveau code.
        /// </summary>
        /// <returns>Le code généré</returns>

        public Code GenererCode()
        {
            return new Code(TailleCodeMaximum);
        }

        /// <summary>
        /// Initialise le premier joueur à jouer.
        /// </summary>
        public void CommencerLaPartie()
        {
            joueurCourant = 0;
        }


        /// <summary>
        /// Vérifie si la partie est terminée.
        /// </summary>
        /// <returns>True si la partie est terminée, sinon False.</returns>
        public bool EstTerminee()
        {
            if (!joueurCourant.HasValue || joueurCourant != 0)
                return false;

            if (JoueurCourant().Plateau.Tour > TourMaximum)
                return true;

            for (int i = 0; i < joueurs.Length; ++i)
            {
                if (joueurs[i].Plateau.Victoire)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Obtient les joueurs gagnants de la partie.
        /// </summary>
        /// <returns>La liste des joueurs gagnants.</returns>
        public IEnumerable<Joueur> Gagnants()
        {
            Joueur[] gagnants = [];
            for (int i = 0; i < joueurs.Length; ++i)
            {
                if (joueurs[i].Plateau.Victoire)
                {
                    gagnants = gagnants.Append(joueurs[i]).ToArray();
                }
            }

            return gagnants;
        }

        /// <summary>
        /// Obtient les joueurs perdants de la partie.
        /// </summary>
        /// <returns>La liste des joueurs perdants.</returns>
        public IEnumerable<Joueur> Perdants()
        {
            Joueur[] perdants = [];
            for (int i = 0; i < joueurs.Length; ++i)
            {
                if (!joueurs[i].Plateau.Victoire)
                {
                    perdants = perdants.Append(joueurs[i]).ToArray();
                }
            }

            return perdants;
        }
    }
}
