using MinesweeperControl;
using MinesweeperSolver;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Numerics;
using static MinesweeperControl.GameDescription;
using static MinesweeperControl.MinesweeperGame;

namespace Bulk_Runner {
    class BulkRunner {

        private static readonly bool pauseOnWin = false;
        private static readonly bool playUntilWin = false;
        private static GameAction[] firstPlay;

        private static int[] deathTable = new int[50]; 

        static void Main(string[] args) {

            GameDescription description = GameDescription.EXPERT_SAFE;
            //GameDescription description = new GameDescription(30, 24, 225, GameType.Safe);
            //GameDescription description = new GameDescription(100, 100, 1500, GameType.Zero);
            //GameDescription description = new GameDescription(50, 50, 500, GameType.Safe);
            //GameDescription description = new GameDescription(8, 8, 34, GameType.Safe);

            if (description.gameType == GameType.Zero) {
                firstPlay = new GameAction[] { new GameAction(3, 3, ActionType.Clear) };
            } else {
                firstPlay = new GameAction[] { new GameAction(0, 0, ActionType.Clear) };
            }

            int seedGen = new Random().Next();
            //int seedGen = 1104105816;

            Random rng = new Random(seedGen);

            int run = 100000;
            int steps = 100;

            int won = 0;
            int lost = 0;
            int deaths = 0;

            SolverMain.Initialise();

            Write("using generation seed " + seedGen + " to run " + run + " games of minesweeper " + description.AsText());
            Write("--- Press Enter to start ---");

            Console.ReadLine();

            long start = DateTime.Now.Ticks;

            for (int i=0; i < run; i++) {

                int seed = rng.Next();

                MinesweeperGame game = new MinesweeperGame(description, seed, !playUntilWin);

                //Write("Seed " + game.seed + " starting");

                GameStatus status = AutoPlayRunner(game);

                int died = game.GetDeaths();
                if (died < deathTable.Length) {
                    deathTable[died]++;
                } else {
                    deathTable[deathTable.Length - 1]++;
                }


                deaths = deaths + died;

                if (status == GameStatus.Lost) {
                    lost++;
                } else if (status == GameStatus.Won) {
                    won++;
                    if (pauseOnWin) {
                        Write("Seed " + game.seed + " won");
                        Write("--- Press Enter to continue ---");
                        Console.ReadLine();
                    }
                } else {
                    Write("Seed " + game.seed + " : Unexpected game status from autoplay " + status);
                }

                if ((i + 1) % steps == 0) {
                    Write("Seed " + game.seed + " finished. Games won " + won + " out of " + (i + 1));
                }

            }

            long duration = (DateTime.Now.Ticks - start ) / 10000;


            Write("Games won " + won + ", lost " + lost + " out of " + run + " in " + duration + " milliseconds.");

            double winRate = (won * 10000 / run) / 100d;

            Write("Win rate " + winRate + "%");

            Write("Deaths " + deaths + " average deaths per game " + (deaths * 1000 / run) / 1000d);

            for (int i=0; i < deathTable.Length - 1; i++) {
                Write("Died " + i + " times in " + deathTable[i] + " games");
            }
            Write("Died >=" + (deathTable.Length - 1) + " times in " + deathTable[deathTable.Length - 1] + " games");

            Console.ReadLine();


        }

        // this method runs on a different thread. gameNumber can be changed by clicking chosing a new game from the UI thread.
        private static GameStatus AutoPlayRunner(MinesweeperGame game) {

            //long start = DateTime.Now.Ticks;

            SolverActionHeader solverActions;

            GameResult result = game.ProcessActions(firstPlay);

            SolverInfo solverInfo = new SolverInfo(game.description);

            while (result.status == GameStatus.InPlay) {

                solverInfo.AddInformation(result);  // let the solver know what has happened

                solverActions = SolverMain.FindActions(solverInfo);   // pass the solver info into the solver and see what it comes up with

                if (solverActions.solverActions.Count == 0) {
                    Write("No actions returned by the solver!!");
                    break;
                }

                result = game.ProcessActions(solverActions.solverActions);

                //Write("Game controller returned " + result.actionResults.Count + " results from this action");

                //foreach (SolverAction action in solverActions) {
                //    Write("Playing " + action.AsText() + " probability " + action.safeProbability);
                //}

            }

            //long end = DateTime.Now.Ticks;

            //Write("game took " + (end - start) + " ticks");


            return result.status;
        }

        private static void Write(String text) {
            Console.WriteLine(text);
        }
    }
}
