#include "game.hpp"
#include "player.hpp"
#include "server.hpp"
#include <arpa/inet.h>
#include <functional>
#include <iostream>
#include <map>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wordle-de.pb.h>

Engine *eng;
Server *srv;
std::map<int, Player *> players;

void connected(uint16_t fd) { std::cout << "Connected" << std::endl; }
void disconnected(uint16_t fd) { std::cout << "Disconnected" << std::endl; }
void received(uint16_t fd, char *buffer) {

  wordle_de::Message msg;
  msg.ParseFromString(buffer);

  switch (msg.msg_case()) {
  case wordle_de::Message::kLogin: {
    auto login = msg.mutable_login();
    std::cout << "Received Login" << std::endl;
    std::string username = login->username();
    std::string password = login->password();
    std::cout << "Username: " << username << ", Password: " << password
              << std::endl;
    // check if player is registered
    if (players.contains(fd) && players.at(fd)->getUsername() == username) {
      std::cout << "player known" << std::endl;
      auto player = players.at(fd);
      // authenticate player
      if (player->authenticate(password)) {
        std::cout << "Player '" << username << "' authenticated" << std::endl;
      } else {
        std::cout << "wrong password" << std::endl;
        srv->sendLoginAck(fd, false, "wrong password");
      }
    }
    auto player = new Player(username, password);
    player->setWord(eng->getWord());
    players[fd] = player;
    srv->sendLoginAck(fd, true);
    auto cb = [player, fd](const std::string &w) {
      player->setWord(w);
      auto msg = player->getGameState().serialize(true);
      srv->sendMessage(fd, msg.c_str());
    };
    eng->registerNewWordCallback(cb);
    break;
  }
  case wordle_de::Message::kGuess: {
    if (!msg.has_guess()) {
      throw "malformed message";
    }
    auto guess = msg.guess();
    std::cout << "Received Guess: " << guess.guess() << std::endl;
    auto player = players.at(fd);
    srv->sendGuessAck(fd, player->guess(guess.guess()));
    break;
  }
  case wordle_de::Message::kGameState:
    break;
  default:
    break;
  }
}

int main(void) {
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  // initialize server
  Server::createInstance();
  srv = Server::getInstance();
  srv->onConnect(connected);
  srv->onDisconnect(disconnected);
  srv->onInput(received);
  std::cout << "Run..." << std::endl;
  srv->init();

  // initialize game engine
  Engine::createInstance();
  eng = Engine::getInstance();
  eng->start(60);

  // run the server
  while (true) {
    srv->run();
  }
  return 0;
}