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

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

std::map<int, const char *> port_classes = {{1, "BBS"}, {2, "BSB"}, {3, "SBB"},
                                            {4, "SSB"}, {5, "SBS"}, {6, "BSS"},
                                            {7, "SSS"}, {8, "BBB"}, {9, "BBB"}};

/* From Galaxy.py
PORT_CLASSES = {
    1: "BBS",
    2: "BSB",
    3: "SBB",
    4: "SSB",
    5: "SBS",
    6: "BSS",
    7: "SSS",
    8: "BBB",
}*/

TEST(ports, get_buysell) {
  for (int type = 1; type < 10; ++type) {
    buysell expected;
    const char *flags;

    flags = port_classes[type];
    for (int x = 0; x < 3; ++x) expected.foe[x] = flags[x] == 'B';
    buysell result = get_buysell(type);
    for (int x = 0; x < 3; ++x)
      EXPECT_EQ(result.foe[x], expected.foe[x])
          << "type: " << type << " pos: " << x;
  }
}

TEST(ports, invert_buysell) {
  for (int type = 1; type < 10; ++type) {
    buysell expected;
    const char *flags;

    flags = port_classes[type];
    for (int x = 0; x < 3; ++x) expected.foe[x] = flags[x] != 'B';
    buysell result = get_buysell(type);
    buysell invert = invert_buysell(result);
    for (int x = 0; x < 3; ++x)
      EXPECT_EQ(invert.foe[x], expected.foe[x])
          << "type: " << type << " pos: " << x;
  }
}

TEST(ports, text_from_type) {
  for (int type = 1; type < 10; ++type) {
    buysell_text expected;
    const char *flags;

    flags = port_classes[type];
    for (int x = 0; x < 3; ++x) expected.txt[x] = flags[x];
    buysell_text result = text_from_type(type);
    EXPECT_EQ(result, expected) << "type: " << type;
  }
}

TEST(ports, text_from_buysell) {
  for (int type = 1; type < 10; ++type) {
    buysell source = get_buysell(type);
    buysell_text expected;
    const char *flags;

    flags = port_classes[type];
    for (int x = 0; x < 3; ++x) expected.txt[x] = flags[x];
    buysell_text result = text_from_buysell(source);
    EXPECT_EQ(result, expected) << "type: " << type;
  }
}

TEST(ports, type_from_buysell) {
  for (int type = 1; type < 9; ++type) {
    buysell source = get_buysell(type);
    int result = type_from_buysell(source);
    EXPECT_EQ(result, type) << "type: " << type;
  }
}

struct pair {
  int t1;
  int t2;
  friend bool operator<(const pair &lhs, const pair &rhs) {
    if (lhs.t1 == rhs.t1) {
      return lhs.t2 < rhs.t2;
    }
    return lhs.t1 < rhs.t1;
  };
  friend bool operator==(const pair &lhs, const pair &rhs) {
    return (lhs.t1 == rhs.t1) && (lhs.t2 == rhs.t2);
  };
};

TEST(ports, trade_types) {
  std::map<pair, int> expected;
  for (int x = 0; x < 9; ++x) {
    pair p{x, x};  // ; p.t1 = x; p.t2 = 2;
    expected[p] = 0;
  }

  expected[pair{1, 2}] = 1;
  expected[pair{1, 4}] = 1;
  expected[pair{2, 5}] = 1;
  expected[pair{4, 5}] = 1;

  // I'm checking 0's and 1's.
  expected[pair{1, 3}] = 2;
  expected[pair{2, 3}] = 2;
  expected[pair{4, 6}] = 2;
  expected[pair{5, 6}] = 2;

  /*
  GTEST_COUT << "size:" << expected.size() << std::endl;

  for (auto const & i : expected ) {
    GTEST_COUT << i.first.t1 << "," << i.first.t2 << " :" << i.second <<
  std::endl;
  }

  GTEST_COUT << "Done!" << std::endl;
  */

  for (int p1 = 1; p1 <= 8; ++p1) {
    for (int p2 = p1; p2 <= 8; ++p2) {
      // GTEST_COUT << "Type " << p1 << " and " << p2 << std::endl;
      int t = trade_type(p1, p2);
      int t2 = trade_type(p2, p1);
      EXPECT_EQ(t, t2) << "Comparing reversed types";
      pair p{p1, p2};
      auto r = expected.find(p);
      if (r != expected.end()) {
        EXPECT_EQ(t, r->second) << "Comparision";
      } else {
        GTEST_COUT << "TODO: Need type for " << p1 << " " << text_from_type(p1)
                   << " , " << p2 << " " << text_from_type(p2) << " : " << t
                   << std::endl;
      }
    }
  }
}

TEST(ports, parse_portcim) {
  // This really needs to be checked against real lines from a log file
  // THis was copied directly from client (indentation may be off)
  std::map<std::string, port> data = {
      {"  2 - 2420 100%    612  35% - 2020 100% ",  // BSB
       {2, 2, {2420, 612, 2020}, {100, 35, 100}}},
      {"  4 - 2880 100% -  275  23%     61   6% ",  // BBS
       {4, 1, {2880, 275, 61}, {100, 23, 6}}},
      {"  6 -  820 100%   1952  89% - 2680 100% ",  // BSB
       {6, 2, {820, 1952, 2680}, {100, 89, 100}}},
      {"  8 - 1000 100% -  855  85% - 1000 100% ",  // BBB
       {8, 8, {1000, 855, 1000}, {100, 85, 100}}},
      {" 20 - 1708  97% -  710  56%    287  15% ",  // BBS
       {20, 1, {1708, 710, 287}, {97, 56, 15}}},
      {" 23 - 2120 100% -  709  40%   1902  69% ",  // BBS
       {23, 1, {2120, 709, 1902}, {100, 40, 69}}},
      {" 28   1511  98% -  478  29%    589  35% ",  // SBS
       {28, 5, {1511, 478, 589}, {98, 29, 35}}},
      {" 29    913  56% -  970 100% - 1990 100% ",  // SBB
       {29, 3, {913, 970, 1990}, {56, 100, 100}}}};

  /*
  // If you could make this a map or something better please improve
  std::vector<port> ports;
  ports.push_back( port{ 2, 2, {2420, 612, 2020}, {100,35,100} });

  struct port p;
  p.sector = 2;
  p.type = 2;
  p.amount[0] = 2420;
  p.amount[1] = 612;
  p.amount[2] = 2020;
  p.percent[0] = 100;
  p.percent[1] = 35;
  p.percent[2] = 100;
  ports.push_back(p);
  p.sector = 4;
  p.type = 1;
  p.amount[0] = 2880;
  p.amount[1] = 275;
  p.amount[2] = 61;
  p.percent[0] = 100;
  p.percent[1] = 23;
  p.percent[2] = 6;
  ports.push_back(p);
    */

  for (auto testdata : data) {
    port parse = parse_portcim(testdata.first);
    EXPECT_EQ((int)parse.sector, (int)testdata.second.sector)
        << "Text: [" << testdata.first << "]";
    if (parse.sector != 0) {
      EXPECT_EQ(parse.type, testdata.second.type);
      for (int x = 0; x < 3; ++x) {
        EXPECT_EQ(parse.amount[x], testdata.second.amount[x])
            << "Sector:" << parse.sector;
        EXPECT_EQ(parse.percent[x], testdata.second.percent[x])
            << "Sector:" << parse.sector;
      }
    }
  }
  /*
  port parse = parse_portcim(data[0]);
  EXPECT_EQ(parse.sector, 2 );
  EXPECT_EQ(parse.type, 2);
  EXPECT_EQ(parse.amount[0], 2420);

  EXPECT_EQ(parse.sector, ports[0].sector);
  EXPECT_EQ(parse.type, ports[0].type);
    */
  /*
  this can't work.  trying to compare "pointers" .. that's why the numbers are
  huge: Expected equality of these values: parse.amount Which is: 0x7fffc5ef83f6
  ports[0].amount
    Which is: 0x5556513ddb94
  */

  // EXPECT_EQ(parse.amount, ports[0].amount);
  // EXPECT_EQ(parse.percent, ports[0].percent);
}

}  // namespace