#include <array>
#include <map>
#include <string>
#include <vector>

#include "director.h"
#include "galaxy.h"
#include "gtest/gtest.h"

/*

How can I add logging, but not really add/use it?

*/

#define GTEST_COUT std::cerr << "[          ] [ INFO ]"

namespace {

TEST(director, director_debugging) {
  Director dir;
  std::vector<std::string> client;
  std::vector<std::string> server;
  dir.to_client = [&client](const std::string line) { client.push_back(line); };
  dir.to_server = [&server](const std::string line) { server.push_back(line); };

  // activating the game gets this over to dir.galaxy.username.
  dir.username = "test";

  // should I setup galaxy-N-test.yaml ?  Probably yes.
  std::string lines[] = {
      "TradeWars Game Server                                     Copyright (C) "
      "EIS",
      "Selection (? for menu): N",
      "Trade Wars 2002 Win32 module now loading.",
      "   ==-- Trade Wars 2002 --==",
      "Enter your choice: ",
      "^Command [TL=00:00:00]:[2985] (?=Help)? :"};

  for (auto line : lines) {
    if (line[0] == '^') {
      dir.server_prompt(line.substr(1), line.substr(1));
    } else if (line[0] == '!') {
      // client input
      dir.client_input(line.substr(1));
    } else {
      dir.server_line(line, line);
    }
  }
  EXPECT_EQ(client[0],
            "\rTradeWars Proxy v2++ READY (~ or ESC to activate)\n\r");
  client.clear();
  dir.client_input("~");

  for (auto line : client) {
    GTEST_COUT << line << std::endl;
  }
}

/* // my save rountine handles sequences.  This is a NOP.
TEST(director, director_galaxy_save) {
  Director dir;

  dir.galaxy.username = "test";
  dir.galaxy.game = 'Z';
  // This causes a YAML::Node Sequence
  dir.galaxy.meta["trade"][10963][0] = 1;
  dir.galaxy.save();

  EXPECT_TRUE(1) << "No exception, this is good!";
}
*/

TEST(director, director_parsing_density) {
  Director dir;
  std::vector<std::string> client;
  std::vector<std::string> server;
  dir.to_client = [&client](const std::string line) { client.push_back(line); };
  dir.to_server = [&server](const std::string line) { server.push_back(line); };

  dir.username = "test";
  std::string lines[] = {
      "TradeWars Game Server                                     Copyright (C) "
      "EIS",
      "Selection (? for menu): N",
      "^Command [TL=00:00:00]:[2985] (?=Help)? :",
      "!s",
      "Command [TL=00:00:00]:[926] (?=Help)? : S",
      "",
      "Long Range Scan",
      "^Select (H)olo Scan or (D)ensity Scan or (Q)uit? [D] ",
      "!d",
      "Select (H)olo Scan or (D)ensity Scan or (Q)uit? [D] D",
      "",
      "                          Relative Density Scan",
      "------------------------------------------------------------------------"
      "-----",
      "Sector    70  ==>              0  Warps : 6    NavHaz :     0%    Anom "
      ": No",
      "Sector   441  ==>            100  Warps : 2    NavHaz :     0%    Anom "
      ": No",
      "Sector ( 575) ==>           1000  Warps : 2    NavHaz :     15%    Anom "
      ": Yes",
      "Sector   600  ==>             40  Warps : 6    NavHaz :     0%    Anom "
      ": No",
      "Sector   629  ==>              1  Warps : 4    NavHaz :     0%    Anom "
      ": No",
      "Sector   711  ==>            101  Warps : 6    NavHaz :     0%    Anom "
      ": No",
      ""};

  for (auto line : lines) {
    if (line[0] == '^') {
      dir.server_prompt(line.substr(1), line.substr(1));
    } else if (line[0] == '!') {
      // client input
      dir.client_input(line.substr(1));
    } else {
      dir.server_line(line, line);
    }
  }

  std::array<density, 6> dense = {{{70, 0, 6, 0, false, true},
                                   {441, 100, 2, 0, false, true},
                                   {575, 1000, 2, 15, true, false},
                                   {600, 40, 6, 0, false, true},
                                   {629, 1, 4, 0, false, true},
                                   {711, 101, 6, 0, false, true}}};

  for (auto const& s : dense) {
    auto d = dir.galaxy.dscan.find(s.sector);
    EXPECT_EQ(d, s) << "Sector " << s.sector << " density";
  }

  // Check that each sector was correctly processed
  std::vector<int> sectors = {70, 441, 575, 600, 629, 711};

  json sector_data;
  sector_data[70]["density"] = 0;
  sector_data[70]["warps"] = 6;
  sector_data[70]["navhaz"] = 0;
  sector_data[70]["anom"] = false;
  sector_data[70]["known"] = true;
  sector_data[441]["density"] = 100;
  sector_data[441]["warps"] = 2;
  sector_data[441]["navhaz"] = 0;
  sector_data[441]["anom"] = false;
  sector_data[441]["known"] = true;
  sector_data[575]["density"] = 1000;
  sector_data[575]["warps"] = 2;
  sector_data[575]["navhaz"] = 15;
  sector_data[575]["anom"] = true;
  sector_data[575]["known"] = false;
  sector_data[600]["density"] = 40;
  sector_data[600]["warps"] = 6;
  sector_data[600]["navhaz"] = 0;
  sector_data[600]["anom"] = false;
  sector_data[600]["known"] = true;
  sector_data[629]["density"] = 1;
  sector_data[629]["warps"] = 4;
  sector_data[629]["navhaz"] = 0;
  sector_data[629]["anom"] = false;
  sector_data[629]["known"] = true;
  sector_data[711]["density"] = 101;
  sector_data[711]["warps"] = 6;
  sector_data[711]["navhaz"] = 0;
  sector_data[711]["anom"] = false;
  sector_data[711]["known"] = true;

  for (auto sector : sectors) {
    // GTEST_COUT << "Testing Sector " << sector << std::endl;
    EXPECT_EQ((int)dir.galaxy.meta["density"][sector]["density"],
              (int)sector_data[sector]["density"])
        << "Sector " << sector << " density";
    EXPECT_EQ((int)dir.galaxy.meta["density"][sector]["warps"],
              (int)sector_data[sector]["warps"])
        << "Sector " << sector << " warps";
    EXPECT_EQ((int)dir.galaxy.meta["density"][sector]["navhaz"],
              (int)sector_data[sector]["navhaz"])
        << "Sector " << sector << " navhaz";
    EXPECT_EQ((bool)dir.galaxy.meta["density"][sector]["anom"],
              (bool)sector_data[sector]["anom"])
        << "Sector " << sector << " anom";
    EXPECT_EQ((bool)dir.galaxy.meta["density"][sector]["known"],
              (bool)sector_data[sector]["known"])
        << "Sector " << sector << " known";
  }
}

}  // namespace