// Copyright 2019 DeepMind Technologies Ltd. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <random>

#include "open_spiel/bots/stockfish/stockfish_bot.h"
#include "open_spiel/games/kriegspiel.h"
#include "open_spiel/algorithms/kriegspiel/pimc.h"
#include "open_spiel/algorithms/kriegspiel/infoset.h"
#include "open_spiel/algorithms/kriegspiel/stats_collector.h"

#include "open_spiel/abseil-cpp/absl/random/distributions.h"
#include "open_spiel/spiel.h"
#include "open_spiel/spiel_bots.h"
#include "open_spiel/spiel_utils.h"
#include "open_spiel/algorithms/evaluate_bots.h"
#include "open_spiel/games/chess/pgn.h"

namespace open_spiel {
namespace {

void RunWhiteGames(int min_state_eval_time, int number_of_games) {
  algorithms::HSInfoset is = algorithms::HSInfoset(time(nullptr), chess::Color::kWhite, 1000);

  std::unique_ptr<stockfish::StockfishBot> sf_bot = stockfish::MakeStockfishBot(10);

  auto pimc_bot = algorithms::PIMCBot(
      2000,
      min_state_eval_time,
      &is,
      [&sf_bot](const chess::ChessBoard &board, int eval_time) {

        std::unordered_map<chess::Move, double, algorithms::ChessMoveHash> action_value_map;
        uci::ResultMove result_move = sf_bot->Step(board, eval_time);
        absl::optional<chess::Move> move = board.ParseLANMove(result_move.move);
        if (!move || !board.IsMoveLegal(*move)) {
          uci::ResultMove r = sf_bot->ReadBestMove();
          result_move = sf_bot->Step(board, eval_time);
          move = board.ParseLANMove(result_move.move);
        }
        action_value_map[*move] = result_move.score;

        return action_value_map;
      },
      {0.0, 0.0, 0.0, 1.0});
  std::mt19937 rng(time(nullptr));

  auto random_bot = MakeUniformRandomBot(0, time(nullptr));


  std::vector<Bot *> bot_ptrs;
  bot_ptrs.push_back(random_bot.get());
  bot_ptrs.push_back(&pimc_bot);

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

    auto game = open_spiel::LoadGame("kriegspiel");
    std::unique_ptr<open_spiel::State> state = game->NewInitialState();
    auto returns = EvaluateBots(state.get(), bot_ptrs,absl::Uniform<int>(rng, 0, std::numeric_limits<int>::max()));


    pgn::KriegspielPGN pgn = pgn::KriegspielPGN(
        down_cast<kriegspiel::KriegspielState>(*state),
        "Vojtech Foret Master Thesis",
        i,
        "PIMC with Stockfish(time=" + std::to_string(min_state_eval_time) + ")",
        "Uniform Random",
        chess::Color::kEmpty);

    std::cout << pgn << std::endl;
  }
}

void RunBlackGames(int min_state_eval_time, int number_of_games) {
  algorithms::HSInfoset is = algorithms::HSInfoset(time(nullptr), chess::Color::kBlack, 1000);

  std::unique_ptr<stockfish::StockfishBot> sf_bot = stockfish::MakeStockfishBot(10);

  auto pimc_bot = algorithms::PIMCBot(
      2000,
      min_state_eval_time,
      &is,
      [&sf_bot](const chess::ChessBoard &board, int eval_time) {

        std::unordered_map<chess::Move, double, algorithms::ChessMoveHash> action_value_map;
        uci::ResultMove result_move = sf_bot->Step(board, eval_time);
        absl::optional<chess::Move> move = board.ParseLANMove(result_move.move);
        if (!move || !board.IsMoveLegal(*move)) {
          uci::ResultMove r = sf_bot->ReadBestMove();
          result_move = sf_bot->Step(board, eval_time);
          move = board.ParseLANMove(result_move.move);
        }
        action_value_map[*move] = result_move.score;

        return action_value_map;
      },
      {0.0, 0.0, 0.0, 1.0});
  std::mt19937 rng(time(nullptr));

  auto random_bot = MakeUniformRandomBot(1, time(nullptr));


  std::vector<Bot *> bot_ptrs;
  bot_ptrs.push_back(&pimc_bot);
  bot_ptrs.push_back(random_bot.get());

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

    auto game = open_spiel::LoadGame("kriegspiel");
    std::unique_ptr<open_spiel::State> state = game->NewInitialState();
    auto returns = EvaluateBots(state.get(), bot_ptrs,absl::Uniform<int>(rng, 0, std::numeric_limits<int>::max()));


    pgn::KriegspielPGN pgn = pgn::KriegspielPGN(
        down_cast<kriegspiel::KriegspielState>(*state),
        "Vojtech Foret Master Thesis",
        i,
        "Uniform Random",
        "PIMC with Stockfish(time=" + std::to_string(min_state_eval_time) + ")",
        chess::Color::kEmpty);

    std::cout << pgn << std::endl;
  }
}

void PlayGames(int min_state_eval_time) {
  for (int i = 0; i < 25; ++i) {
    RunWhiteGames(min_state_eval_time, 1);
    RunBlackGames(min_state_eval_time, 1);
  }

}

}  // namespace
}  // namespace open_spiel

int main(int argc, char** argv) {
  //int min_state_eval_time = std::atoi(argv[1]);
//  open_spiel::PlayGames(50);
  open_spiel::algorithms::ReadResults();
}
// PIMC

// ISMCTS


// RANDOM

//Random Heuristic Uniform Random: 84 - 903 - 13
//Uniform Random Random Heuristic: 22 - 887 - 91