using System;
using System.Collections.Generic;
using TheGameExtreme.model.card;
using TheGameExtreme.model.deck;
using TheGameExtreme.model.@event;
using TheGameExtreme.model.piles;

namespace TheGameExtreme.model.gameActions.classic
{
    public class GameMode
    {

        protected List<GameAction> gameActions;
        public Piles Piles { get; protected set; }
        public int NbCardAtBeginOfTurn { get; set; }
        protected Deck deck;
        protected int nbMaxCard;
        public string Message { get; set; }
        protected bool end;


        #region

        public event EventHandler<EventArgs> EndGame;
        public event EventHandler<PlayerChangedEventArgs> PlayerChanged;
        protected internal void OnEndGame(EventArgs args)
        {
            EndGame?.Invoke(this, args);
        }
        protected internal void OnPlayerChanged(PlayerChangedEventArgs args)
        {
            PlayerChanged?.Invoke(this, args);
        }

        #endregion


        public GameMode(Piles piles, Deck deck)
        {
            gameActions = new List<GameAction>();
            Piles = piles;
            this.deck = deck;
        }

        public void load(int nbPlayer, List<Player> players)
        {
            gameActions.Add(new Piocher(Piles));
            gameActions.Add(new JouerUneCarte(Piles));
            gameActions.Add(new TerminerSonTour(Piles));

            defineNbMaxCard(nbPlayer);
            distribueCard(players);
        }

        protected void defineNbMaxCard(int nbPlayer)
        {
            switch (nbPlayer)
            {
                case 1:
                    nbMaxCard = 8;
                    NbCardAtBeginOfTurn = 8;
                    break;
                case 2:
                    nbMaxCard = 7;
                    NbCardAtBeginOfTurn = 7;
                    break;
                default:
                    nbMaxCard = 6;
                    NbCardAtBeginOfTurn = 6;
                    break;
            }
        }

        protected void quickSort(List<Card> ar, int start, int end)
        {
            if (start < end)
            {
                decimal pivot = ar[end].Value;
                int pIndex = start;
                decimal swap;

                for (int i = start; i < end; i++)
                {
                    if (ar[i].Value < pivot)
                    {
                        swap = ar[pIndex].Value;
                        ar[pIndex].Value = ar[i].Value;
                        ar[i].Value = swap;
                        pIndex++;
                    }
                }

                ar[end].Value = ar[pIndex].Value;
                ar[pIndex].Value = pivot;

                quickSort(ar, start, pIndex - 1);
                quickSort(ar, pIndex + 1, end);
            }
        }

        protected void distribueCard(List<Player> players)
        {
            players.ForEach(player =>
            {
                for (int i = 0; i < nbMaxCard; i++)
                {
                    int r = new Random().Next(0, deck.size() - 1);
                    player.pioche(deck.getCard(r));
                    deck.removeAt(r);
                }
                List<Card> cards = player.getCardList();
                quickSort(cards, 0, cards.Count-1);
            });
        }

        public void pioche(List<Card> currentHand, Player player)
        {
            Message = null;
            ((Piocher)gameActions[0]).pioche(currentHand, deck, player, nbMaxCard);
            quickSort(currentHand, 0, currentHand.Count - 1);
        }

        public bool playCard(decimal valueCard, List<Card> currentHand, int orderedStackSelected, Player player, List<Card> CurrentCardPlayed)
        {
            Message = null;
            if (((JouerUneCarte)gameActions[1]).play(valueCard, currentHand, orderedStackSelected, player, CurrentCardPlayed))
            {
                return true;
            }
            else
            {
                Message = ((JouerUneCarte)gameActions[1]).ErrorMessage;
                return false;
            }
        }

        public bool endTurn(List<Card> currentHand, List<Card> CurrentCardPlayed, Player player)
        {
            Message = null;
            if (((TerminerSonTour)gameActions[2]).end(currentHand, CurrentCardPlayed))
            {
                pioche(currentHand, player);
                CurrentCardPlayed.Clear();
                OnPlayerChanged(null);
                return end;
            }
            else
            {
                Message = ((TerminerSonTour)gameActions[2]).ErrorMessage;
                return false;
            }
        }

        public void TestEndGame(List<Card> currentHand)
        {
            if (((TerminerSonTour)gameActions[2]).Test(currentHand))
            {
                end = false;
            }
            else
            {
                OnEndGame(new EventArgs());
                end = true;
            }
        }

        public string getScore()
        {
            return deck.size().ToString();
        }

        #region Decaler dans un GameAction

        public bool isEndGame(List<Card> currentHand)
        {
            if (currentHand.Count != 0)
            {
                List<Card> playableCard = new List<Card>();
                tryToFindSoluce(playableCard, currentHand);
                return testEndGame(playableCard);
            }
            return false;
        }

        protected void tryToFindSoluce(List<Card> playableCard, List<Card> currentHand)
        {
            currentHand.ForEach(card =>
            {
                if (card.Value > Piles.getStack(0).Peek().Value || card.Value > Piles.getStack(1).Peek().Value || card.Value < Piles.getStack(2).Peek().Value || card.Value < Piles.getStack(3).Peek().Value)
                {
                    playableCard.Add(card);
                }
            });
        }

        protected bool testEndGame(List<Card> playableCard)
        {
            if (playableCard.Count < 2)
            {
                Message = "Le jeu est terminé!\n Désolé, vous avez perdu... Essayez encore!";
                return true;
            }

            return false;
        }

        #endregion
    }
}
