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

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

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


        #region

        public event EventHandler<TopRangeChangedEventArgs> TopRangeChanged;
        public event EventHandler<PlayerChangedEventArgs> PlayerChanged;
        protected internal void OnTopRangeChanged(TopRangeChangedEventArgs args)
        {
            TopRangeChanged?.Invoke(this, args);
        }
        protected internal void OnPlayerChanged(PlayerChangedEventArgs args)
        {
            PlayerChanged?.Invoke(this, args);
        }

        #endregion


        public GameMode()
        {
            gameActions = new List<GameAction>();
        }

        public void load(int nbPlayer, List<Player> players)
        {
            piles = new Piles();

            gameActions.Add(new Piocher(piles));
            gameActions.Add(new JouerUneCarte(piles));
            gameActions.Add(new TerminerSonTour(piles));

            createDeck();
            defineNbMaxCard(nbPlayer);
            distribueCard(players);
        }

        protected void createDeck()
        {
            switch (true)
            {
                case false:
                    deck = new ClassicDeck();
                    break;

                default:
                    deck = new ExtremeDeck();
                    break;
            }
        }

        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 distribueCard(List<Player> players)
        {
            for (int i = 0; i < nbMaxCard; i++)
            {
                players.ForEach(player =>
                {
                    int r = new Random().Next(0, deck.size() - 1);
                    player.pioche(deck.getCard(r));
                    deck.removeAt(r);
                });
            }
        }

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

        public void playCard(int valueCard, List<Card> currentHand, int orderedStackSelected, Player player, List<Card> CurrentCardPlayed)
        {
            Message = null;
            if (((JouerUneCarte)gameActions[1]).play(valueCard, currentHand, orderedStackSelected, player, CurrentCardPlayed))
            {
                OnTopRangeChanged(new TopRangeChangedEventArgs(piles.getStack(orderedStackSelected).Peek(), ((JouerUneCarte)gameActions[1]).OldCard, orderedStackSelected));
            }
            else
            {
                Message = ((JouerUneCarte)gameActions[1]).ErrorMessage;
            }
        }

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

        #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
    }
}
