using CoreLibrary;
using CoreLibrary.Exceptions;
using Xunit;

namespace UnitTesting
{
    public class CodeUT
    {
        [Fact]
        public void TestFirstConstructorValidArguments()
        {
            Code code = new Code(4);
            Assert.NotNull(code);
            Assert.Equal(4, code.Jetons().Count());
            Assert.Equal(0, code.NbJetons);
        }

        [Fact]
        public void TestConstructorInvalidArguments()
        {
            Assert.Throws<TailleCodeException>(() => new Code(0));
            Assert.Throws<TailleCodeException>(() => new Code(-1));
        }

        [Fact]
        public void TestSecondConstructorValidArguments()
        {
            Jeton[] jetons = [new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLEU)];

            Code code = new Code(jetons);
            Assert.NotNull(code);
            Assert.Equal(3, code.Jetons().Count());
            Assert.Equal(3, code.NbJetons);
        }

        [Fact]
        public void TestSecondConstructorInvalidArguments()
        {
            Assert.Throws<TailleCodeException>(() => new Code([]));
        }

        [Fact]
        public void TestAjouterJetonValid()
        {
            Jeton jeton = new Jeton(Couleur.JAUNE);
            Code code = new Code(3);
            code.AjouterJeton(jeton);
            Assert.Equal(1, code.NbJetons);
            Assert.Equal(jeton, code.Jetons().ElementAt(0));
        }

        [Fact]
        public void TestAjouterJetonInvalid()
        {
            Code code = new Code([new Jeton(Couleur.NOIR)]);
            Assert.Throws<CodeCompletException>(() => code.AjouterJeton(new Jeton(Couleur.ROUGE)));
        }

        [Fact]
        public void TestSupprimerDernierJetonValid()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            code.SupprimerDernierJeton();
            Assert.Equal(2, code.NbJetons);
        }

        [Fact]
        public void TestSupprimerDernierJetonInvalid()
        {
            Code code = new Code(4);
            Assert.Throws<CodeVideException>(() => code.SupprimerDernierJeton());
        }

        [Fact]
        public void TestRecupererJetonValid()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            Jeton jetonAttendu = new Jeton(Couleur.BLEU);
            Jeton jeton = code.RecupererJeton(1);
            Assert.Equal(jetonAttendu.Couleur, jeton.Couleur);
        }

        [Fact]
        public void TestRecupererJetonInvalid()
        {
            Code code = new Code(4);
            Assert.Throws<IndiceCodeException>(() => code.RecupererJeton(-1));
            Assert.Throws<IndiceCodeException>(() => code.RecupererJeton(4));
        }

        [Fact]
        public void TestRecupererJetonNull()
        {
            Code code = new Code(4);
            Assert.Throws<IndiceCodeException>(() => code.RecupererJeton(1));
        }

        [Fact]
        public void TestJetonsValid()
        {
            Jeton[] jetonsAttendus = [new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLEU)];
            Code code = new Code(jetonsAttendus);
            IEnumerable<Jeton?> lesJetons = code.Jetons();

            Assert.Equal(jetonsAttendus.Length, lesJetons.Count());

            int index = 0;
            foreach (Jeton jetonAttendu in jetonsAttendus)
            {
                Assert.Equal(jetonAttendu.Couleur, lesJetons.ElementAt(index)?.Couleur);
                index++;
            }
        }

        [Fact]
        public void TestEstCompletValid()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            bool estComplet = code.EstComplet();
            Assert.True(estComplet);
        }

        [Fact]
        public void TestEstCompletInvalid()
        {
            Code code = new Code(3);
            bool estComplet = code.EstComplet();
            Assert.False(estComplet);
        }

        [Fact]
        public void TestTailleMaximaleValid()
        {
            Jeton[] jetons = [new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLEU)];
            Code code = new Code(jetons);
            int tailleMaximale = code.TailleMaximale();

            Assert.Equal(jetons.Length, tailleMaximale);
        }

        [Fact]
        public void TestComparerValide()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            Code autreCode = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);

            IEnumerable<Indicateur> indicateurs = code.Comparer(autreCode);

            Assert.Equal(3, indicateurs.Count());
            Assert.Contains(Indicateur.BONNEPLACE, indicateurs);
            Assert.DoesNotContain(Indicateur.BONNECOULEUR, indicateurs);
        }

        [Fact]
        public void TestComparerBonnePlace()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            Code autreCode = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.NOIR)]);

            IEnumerable<Indicateur> indicateurs = code.Comparer(autreCode);

            Assert.Equal(2, indicateurs.Count());
            Assert.Contains(Indicateur.BONNEPLACE, indicateurs);
            Assert.DoesNotContain(Indicateur.BONNECOULEUR, indicateurs);
        }

        [Fact]
        public void TestComparerBonneCouleur()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            Code autreCode = new Code([new Jeton(Couleur.BLEU), new Jeton(Couleur.ROUGE), new Jeton(Couleur.NOIR)]);

            IEnumerable<Indicateur> indicateurs = code.Comparer(autreCode);

            Assert.Equal(2, indicateurs.Count());
            Assert.Contains(Indicateur.BONNECOULEUR, indicateurs);
            Assert.DoesNotContain(Indicateur.BONNEPLACE, indicateurs);
        }

        [Fact]
        public void TestComparerBonnePlaceEtCouleur()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            Code autreCode = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLANC), new Jeton(Couleur.BLEU)]);

            IEnumerable<Indicateur> indicateurs = code.Comparer(autreCode);

            Assert.Equal(3, indicateurs.Count());
            Assert.Contains(Indicateur.BONNEPLACE, indicateurs);
            Assert.Contains(Indicateur.BONNECOULEUR, indicateurs);
        }

        [Fact]
        public void TestComparerDifferent()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            Code autreCode = new Code([new Jeton(Couleur.VERT), new Jeton(Couleur.JAUNE), new Jeton(Couleur.NOIR)]);
            IEnumerable<Indicateur> indicateurs = code.Comparer(autreCode);

            Assert.Empty(indicateurs);
        }

        [Fact]
        public void TestComparerMonCodeIncomplet()
        {
            Code code = new Code(3);
            Code autreCode = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            IEnumerable<Indicateur> indicateurs = code.Comparer(autreCode);

            Assert.Empty(indicateurs);
        }

        [Fact]
        public void TestComparerSonCodeIncomplet()
        {
            Code code = new Code([new Jeton(Couleur.ROUGE), new Jeton(Couleur.BLEU), new Jeton(Couleur.BLANC)]);
            Code autreCode = new Code(3);
            IEnumerable<Indicateur> indicateurs = code.Comparer(autreCode);

            Assert.Empty(indicateurs);
        }

    }

}
