using CoreLibrary.Exceptions;

namespace CoreLibrary
{
    /// <summary>
    /// Représente un code composé de jetons.
    /// </summary>
    public class Code
    {
        private readonly Jeton?[] lesJetons;

        /// <summary>
        /// Obtenir le nombre de jetons dans le code.
        /// </summary>
        public int NbJetons { get; private set; } = 0;

        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="Code"/> avec la longueur de code spécifiée.
        /// </summary>
        /// <param name="tailleCode">La longueur du code.</param>
        /// <exception cref="TailleCodeException">Levée lorsque la longueur du code spécifiée est inférieure ou égale à zéro.</exception>
        public Code(int tailleCode)
        {       
            if(tailleCode <= 0)
            {
                throw new TailleCodeException(tailleCode);
            }

            lesJetons = new Jeton?[tailleCode];
        }

        /// <summary>
        /// Initialise une nouvelle instance de la class <see cref="Code"/> avec les jetons spécifiés.
        /// </summary>
        /// <param name="jetons">Les jetons pour initaliser le code.</param>
        /// <exception cref="TailleCodeException">Levée lorsque la collection de jetons spécifiée est vide.</exception>
        public Code(IEnumerable<Jeton> jetons)
        {
            if (!jetons.Any())
            {
                throw new TailleCodeException(jetons.Count());
            }

            lesJetons = new Jeton?[jetons.Count()];
            foreach(Jeton jeton in jetons)
            {
                AjouterJeton(jeton);
            }
        }

        /// <summary>
        /// Ajoute un jeton au code.
        /// </summary>
        /// <param name="jeton">Le jeton à ajouter</param>
        /// <exception cref="CodeCompletException">Levée lorsque le code est plein.</exception>
        public void AjouterJeton(Jeton jeton)
        {
            if (NbJetons == TailleMaximale())
            {
                throw new CodeCompletException();
            }

            lesJetons[NbJetons++] = jeton;
        }

        /// <summary>
        /// Supprime le dernier jeton ajouté au code.
        /// </summary>
        /// <exception cref="CodeVideException">Levée lorsque le code est vide.</exception>
        public void SupprimerDernierJeton()
        {
            if(NbJetons == 0)
            {
                throw new CodeVideException();
            }
                
            lesJetons[--NbJetons] = null;
        }

        /// <summary>
        /// Récupère le jeton à l'indice spécifié dans le code.
        /// </summary>
        /// <param name="indice">L'indice du jeton a récupéré.</param>
        /// <returns>Le jeton situé à l'indice spécifié.</returns>
        /// <exception cref="IndiceCodeException">Levée lorsque l'indice est supérieur à la taille maximale du code, inférieur à 0 ou qu'il n'y a pas de jeton à l'indice spécifié</exception>
        public Jeton RecupererJeton(int indice)
        {
            if(indice < 0 || indice >= TailleMaximale())
                throw new IndiceCodeException(indice, NbJetons-1);
            
            Jeton? jeton = lesJetons[indice];

            if (!jeton.HasValue)
                throw new IndiceCodeException(indice, NbJetons-1);

            return jeton.Value;
        }

        /// <summary>
        /// Récupère une énumération des jetons dans le code.
        /// </summary>
        /// <returns>Enumération des jetons du code</returns>
        public IEnumerable<Jeton?> Jetons()
        {
            return lesJetons;
        }


        /// <summary>
        /// Vérifie si le code est complet.
        /// </summary>
        /// <returns>True si le code est complet, sinon False.</returns>
        public bool EstComplet()
        {
            return NbJetons == lesJetons.Length;
        }

        /// <summary>
        /// Recupère la taille maximal du code.
        /// </summary>
        /// <returns>Taille maximal du code.</returns>

        public int TailleMaximale()
        {
            return lesJetons.Length;
        }

        /// <summary>
        /// Compare le code avec un autre code et génère des indcateurs de correspondance.
        /// </summary>
        /// <param name="autreCode">Le code à comparer avec le code actuel</param>
        /// <returns>Enumération d'indicateurs de correspondance entre les deux codes.</returns>
        public IEnumerable<Indicateur> Comparer(Code autreCode)
        {
            // Mon code est le code correct, l'autre code est celui qui teste

            Indicateur[] indicateurs = [];

            if (!autreCode.EstComplet())
                return indicateurs;

            List<Jeton?> mesJetons = new List<Jeton?>(Jetons());
            List<Jeton?> sesJetons = new List<Jeton?>(autreCode.Jetons());

            for (int i = 0; i < mesJetons.Count; ++i)
            {
                Jeton? monJeton = mesJetons[i];
                Jeton? sonJeton = sesJetons[i];

                if (monJeton.HasValue && sonJeton.HasValue && monJeton.Value.Couleur.Equals(sonJeton.Value.Couleur))
                {
                    indicateurs = indicateurs.Append(Indicateur.BONNEPLACE).ToArray();
                    mesJetons[i] = null;
                    sesJetons[i] = null;
                }
            }


            for (int i = 0; i < sesJetons.Count; ++i)
            {
                Jeton? sonJeton = sesJetons[i];

                

                if (sonJeton.HasValue && mesJetons.Contains(sonJeton.Value))
                {
                    indicateurs = indicateurs.Append(Indicateur.BONNECOULEUR).ToArray();
                    mesJetons[mesJetons.IndexOf(sonJeton)] = null;
                    sesJetons[i] = null;
                }
            }

            return indicateurs;
        }
    }
}


