using System;
namespace GoFish
{
    using System.Collections.Generic;
    using System.Linq;

    public class GameController
    {
        private GameState gameState;
        public bool GameOver { get { return gameState.GameOver; } }
        public Player HumanPlayer { get { return gameState.HumanPlayer; } }
        public IEnumerable<Player> Opponents { get { return gameState.Opponents; } }

        public string Status { get; private set; }

        /// <summary>
        /// Tworzy nowy obiekt typu GameController.
        /// </summary>
        /// <param name="humanPlayerName">Imię gracza-człowieka</param>
        /// <param name="computerPlayerNames">Nazwy graczy sterowanych przez komputer</param>
        public GameController(string humanPlayerName, IEnumerable<string> computerPlayerNames)
        {
            gameState = new GameState(humanPlayerName, computerPlayerNames, new Deck().Shuffle());
            Status = $"Rozpoczynanie nowej gry z graczami {string.Join(", ", gameState.Players)}";
        }

        /// <summary>
        /// Rozgrywa następną kolejkę. Kończy grę, jeśli nikt nie ma już kart.
        /// </summary>
        /// <param name="playerToAsk">Gracz, którego człowiek prosi o kartę</param>
        /// <param name="valueToAskFor">Wartość karty, o jaką prosi człowiek</param>
        public void NextRound(Player playerToAsk, Values valueToAskFor)
        {
            Status = gameState.PlayRound(gameState.HumanPlayer, playerToAsk,
                                         valueToAskFor, gameState.Stock) + Environment.NewLine;

            ComputerPlayersPlayNextRound();

            Status += string.Join(Environment.NewLine,
                                  gameState.Players.Select(player => player.Status));
            Status += $"{Environment.NewLine}Liczba kart na kupce: {gameState.Stock.Count()}";

            Status += Environment.NewLine + gameState.CheckForWinner();
        }


        /// <summary>
        /// Wszyscy gracze sterowani przez komputer, którzy mają karty, rozgrywają kolejkę. Jeśli
        /// człowiekowi skończyły się karty, kupka się wyczerpała i komputer rozgrywa resztę gry.
        /// </summary>
        private void ComputerPlayersPlayNextRound()
        {
            IEnumerable<Player> computerPlayersWithCards;
            do
            {
                computerPlayersWithCards =
                    gameState
                        .Opponents
                        .Where(player => player.Hand.Count() > 0);
                foreach (Player player in computerPlayersWithCards)
                {
                    var randomPlayer = gameState.RandomPlayer(player);
                    var randomValue = player.RandomValueFromHand();
                    Status += gameState
                                  .PlayRound(player, randomPlayer, randomValue, gameState.Stock)
                            + Environment.NewLine;
                }
            } while ((gameState.HumanPlayer.Hand.Count() == 0)
                        && (computerPlayersWithCards.Count() > 0));
        }

        /// <summary>
        /// Rozpoczyna nową grę z tymi samymi nazwami graczy.
        /// </summary>
        public void NewGame()
        {
            Status = "Rozpoczęcie nowej gry";
            gameState = new GameState(gameState.HumanPlayer.Name,
                gameState.Opponents.Select(player => player.Name),
                new Deck().Shuffle());
        }
    }
}
