using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models.Events;

namespace Models.Jeux.Plateau
{


    public class Plateau
    {
        /// <summary>
        /// Evénement permettant l'affichage du plateau
        /// </summary>
        public event EventHandler<ShowingBoardEventArgs> ShowingBoard;

        protected virtual void OnShowingBoard(Plateau plateau)
        {
            ShowingBoard?.Invoke(this, new ShowingBoardEventArgs(plateau));
        }

        /// <summary>
        /// Evénement permettant de déplacer un pion sur le plateau
        /// </summary>
        public event EventHandler<MovingPawnEventArgs> MovingPawn;


        protected virtual void OnMovingPawn(Plateau plateau,Joueur j)
        {
            MovingPawn?.Invoke(this, new MovingPawnEventArgs(plateau,j));
        }

        


        public static decimal Abs(decimal value)
        {  return Math.Abs(value); }

        /// <summary>
        /// Constructeur de la classe plateau, il crée un plateau constitué de cases
        /// puis, ajoute des pions sur ces cases
        /// </summary>
        public Plateau()
        {

            bool b = false;
            for (int x = 0; x < 10; x++)
            {

                if (b == false)
                {
                    for (int y = 0; y < 10; y += 2)
                    {
                        ListeCases.Add(new Case(Couleur.BLANC, x, y));
                        ListeCases.Add(new Case(Couleur.NOIR, x, y + 1));
                    }
                    b = !b;
                }
                else
                {
                    for (int y = 0; y < 10; y += 2)
                    {
                        ListeCases.Add(new Case(Couleur.NOIR, x, y));
                        ListeCases.Add(new Case(Couleur.BLANC, x, y + 1));

                    }
                    b = !b;

                }

            }

            foreach (var c in ListeCases)
            {
                if (c.CouleurCase == Couleur.NOIR && c.PosX < 4)
                {
                    ListePions.Add(new Pion(Couleur.NOIR, c));
                    c.Pion = true;
                }
                if (c.CouleurCase == Couleur.NOIR && c.PosX > 5)
                {
                    ListePions.Add(new Pion(Couleur.BLANC, c));
                    c.Pion = true;
                }

            }

        }

        /// <summary>
        /// Crée le getter et le setter de l'attribut listeCases qui est une liste qui contient des cases
        /// </summary>
        public List<Case> ListeCases
        {
            get
            {
                return listeCases;
            }
            set
            {
                listeCases = value;
            }
        }
        private List<Case> listeCases = new List<Case>();

        /// <summary>
        /// Crée le getter et le setter de l'attribut listeCases qui est une liste qui contient des cases
        /// </summary>
        public List<Pion> ListePions
        {
            get
            {
                return listePions;
            }
            set
            {
                listePions = value;
            }
        }
        private List<Pion> listePions = new List<Pion>();

        /// <summary>
        /// Permet de chercher une case parmis celles présentes sur le plateau
        /// par le biais de 2 coordonées x et y correspondant à la position de la 
        /// case dans le plateau
        /// </summary>
        /// <param name="X">Un objet X de type int qui correspond a une colone du plateau</param>
        /// <param name="Y">Un objet Y de type int qui correspond a une ligne du plateau</param>
        /// <returns></returns>
        public Case rechercheCase(int X,int Y)
        {
            foreach(Case c in listeCases)
            {
                if(c.PosX==X && c.PosY==Y)
                { 
                    return c; 
                }
            }
            return null;
        }
        /// <summary>
        /// Permet de chercher un pion parmis ceux présents sur le plateau
        /// par le biais d'une case donnée.
        /// </summary>
        /// <param name="c">Un objet c de type Case</param>
        /// <returns>Renvoie le pion si il a été trouvé sinon null pour dire que le pion n'est pas sur la plateau </returns>
        public Pion recherchePion(Case c )
        {
            foreach (Pion p in listePions)
            {
                if(p.Pos.PosY==c.PosY &&  p.Pos.PosX==c.PosX)
                { 
                    return p;
                }
            }
            return null;
        }

        /// <summary>
        /// Permet de changer un pion de case en modifiant l'attribut pion de sa case 
        /// à false ainsi qu'en mettant l'attribut pion de la case cible à true et en 
        /// modifiant son attribut pos pour qu'il soit égal à la case cible
        /// </summary>
        /// <param name="p">Un objet p de type Pion qui correspond au pion que l'on veut déplacer</param>
        /// <param name="c">Un objet c de type Case qui correspond à la case sur laquelle on veut déplacer son pion</param>
        virtual public void ChangementCase(Pion p,Case c)
        {
            Case? verifNonNull = ListeCases.FirstOrDefault(item => item == p.Pos);
            if (verifNonNull != null) 
            {
                ListeCases.FirstOrDefault(item => item == p.Pos).Pion = false;
            }
            Case? verifNonNull2 = ListeCases.FirstOrDefault(item => item == c);
            if(verifNonNull2 != null)
            {
                ListeCases.FirstOrDefault(item => item == c).Pion = true;
            }
            Pion? verifNonNull3 = ListePions.FirstOrDefault(item => item == p);
            if( verifNonNull3 != null)
            {
                ListePions.FirstOrDefault(item => item == p).Pos = c;
            }
            
        }

        /// <summary>
        /// Permet de changer un pion en dame afin d'alterer ses déplacements et 
        /// vérifie si la promotion est effectivement possible
        /// </summary>
        /// <param name="p">Un objet p de type Pion qui correspond au pion que l'on veut promouvoir</param>
        public void Promotion(Pion p)
        {
            int maxX = 0;
            if(p.CouleurPion==Couleur.NOIR)
                maxX = 9;
            if(p.Pos.PosX==maxX)
            {
                Dame dame = new Dame(p.CouleurPion, p.Pos);
                ListePions.Remove(p);
                ListePions.Add(dame);
            }
           

        }

       
        /// <summary>
        /// Permet de déplacer un pion sur le plateau et vérifie que le déplacement est valide,
        /// s'il ne l'est pas rien ne se passera 
        /// </summary>
        /// <param name="p">Un objet p de type Pion qui correspond au pion que l'on veut déplacer</param>
        /// <param name="c">Un objet c de type Case qui correspond à la case sur laquelle on veut déplacer son pion</param>
        /// <returns>Si le déplacement est correcte, on renvoie true false sinon</returns>
        public bool deplacer(Pion p,Case c,Joueur j)
        {
            int deplacement = 1;
            int sauter = 2;
            int sauterDeriere = -2;
            int prendreD = -1;
            int prendreDer = 1;
            Case cTemp;
            Pion pTemp;
            if (p is null)
                return false;
            if (c is null)
                return false;
            if (c.Pion == true)
            {
                return false;
            }

            if(j.CouleurDePion!=p.CouleurPion)
            {
                return false;
            }

            if(c.PosX>9 || c.PosX<0)
            {
                return false;
            }

            if(c.PosY >9 || c.PosY<0)
            {
                return false;
            }

            if(p is Dame)
            {
                if(Abs(c.PosX-p.Pos.PosX)==Abs(c.PosY-p.Pos.PosY))
                {
                    int diffX = 1;
                    int diffY = 1;
                    int cptPion = 0;
                    int POSX=p.Pos.PosX;
                    int POSY=p.Pos.PosY;
                    Case derniereCaseAvecPion=c;
                    Pion Ptemp=p;

                    if (c.PosX - p.Pos.PosX < 0)
                        diffX = -1;
                    if(c.PosY - p.Pos.PosY<0)
                        diffY = -1;

                    while(POSX!=c.PosX &&  POSY!=c.PosY)
                    {
                        POSX += diffX;
                        POSY += diffY;
                        if(this.rechercheCase(POSX, POSY).Pion==true)
                        {
                            derniereCaseAvecPion = this.rechercheCase(POSX, POSY);
                            Ptemp = this.recherchePion(derniereCaseAvecPion);
                            if(Ptemp.CouleurPion==p.CouleurPion)
                            {
                                return false;
                            }
                            cptPion += 1;                         
                            
                        }

                    }
                    if (cptPion == 0)
                    {
                        ChangementCase(p, c);
                        return true;

                    }
                    else if (cptPion == 1)
                    {
                        Case? verifNonNull = ListeCases.FirstOrDefault(item => item == derniereCaseAvecPion);
                        if(verifNonNull != null)
                        {
                            ListeCases.FirstOrDefault(item => item == derniereCaseAvecPion).Pion = false;
                        }
                        ListePions.Remove(Ptemp);
                        ChangementCase(p, c);
                        j.NbPions += 1;
                        return true;
                    }
                    


                }
            }


            if (p.CouleurPion == Couleur.BLANC)
            {
                deplacement = -1;
                sauter = -2;
                sauterDeriere = 2;
                prendreD = 1;
                prendreDer = -1;
            }

            if (c.PosX == p.Pos.PosX + deplacement)
            {
                if (c.PosY == p.Pos.PosY + deplacement || c.PosY == p.Pos.PosY - deplacement)
                {
                    ChangementCase(p,c);
                    Promotion(p);
                    return true;
                }
            }
            else
            {
                if (c.PosX == p.Pos.PosX + sauter)
                {
                    if (c.PosY == p.Pos.PosY + sauter || c.PosY == p.Pos.PosY - sauter)
                    {
                        cTemp = this.rechercheCase(c.PosX + prendreD, c.PosY + prendreD);
                        if (cTemp == null || cTemp.Pion==false)
                        {
                            cTemp = this.rechercheCase(c.PosX + prendreD, c.PosY - prendreD);
                            if (cTemp == null)
                                return false;
                        }
                          

                        if (cTemp.Pion == true)
                        {
                            pTemp = this.recherchePion(cTemp);
                            if (pTemp == null)
                            {
                                return false;
                            }
                            if (pTemp.CouleurPion == p.CouleurPion)
                            {
                                return false;
                            }
                            Case? verifNonNull = ListeCases.FirstOrDefault(item => item == cTemp);
                            if(verifNonNull != null)
                            {
                                ListeCases.FirstOrDefault(item => item == cTemp).Pion = false;
                            }
                            ListePions.Remove(pTemp);
                            ChangementCase(p, c);
                            j.NbPions += 1;
                            Promotion(p);
                            return true;
                            
                        }                                    
                    }
                }
                else
                {
                    if (c.PosX == p.Pos.PosX + sauterDeriere)
                    {
                        if (c.PosY == p.Pos.PosY + sauterDeriere || c.PosY == p.Pos.PosY - sauterDeriere)
                        {

                            cTemp = this.rechercheCase(c.PosX + prendreDer, c.PosY + prendreDer);
                            if (cTemp == null || cTemp.Pion==false)
                            {
                                cTemp = this.rechercheCase(c.PosX + prendreDer, c.PosY - prendreDer);
                                if (cTemp == null)
                                    return false;
                            }
                                

                            if (cTemp.Pion == true)
                            {
                                pTemp = this.recherchePion(cTemp);
                                if (pTemp == null)
                                {
                                    return false;
                                }
                                if (pTemp.CouleurPion == p.CouleurPion)
                                {
                                    return false;
                                }
                                Case? verifNonNull = ListeCases.FirstOrDefault(item => item == cTemp);
                                if (verifNonNull != null)
                                {
                                    ListeCases.FirstOrDefault(item => item == cTemp).Pion = false;
                                }
                                ListePions.Remove(pTemp);
                                ChangementCase(p, c);
                                j.NbPions += 1;
                                Promotion(p);
                                return true;

                            }
                        }
                    }
                }
            }
            return false;

        }

        /// <summary>
        /// Appelle l'événement premettant d'afficher le plateau
        /// </summary>
        public void AfficherPlateau()
        {
            OnShowingBoard(this);
        }

        /// <summary>
        /// Appelle l'événement permettant de déplacer un pion
        /// </summary>
        public void MovePawn(Joueur j)
        {
            
            OnMovingPawn(this, j);
        }

    }
       
    
}

