#include "include/client/API.h"

using namespace binom;

void API::connect(QString host, quint16 port) {
  connectImpl(inet_addr(host.toStdString().c_str()), port);
}

bool API::disconnect() {
  if(client.getStatus() == SocketStatus::connected) {
    if(account_ecdh_key_pair) {
      Security::freeKey(account_ecdh_key_pair);
      account_ecdh_key_pair = nullptr;
      emit authenticationStateChanged(false);
    }

    if(!private_aes256_key.isEmpty()) {
      private_aes256_key.clear();
    }

    if(!transport_aes256_key.isEmpty()) {
      transport_aes256_key.clear();
      emit connectionSecureStateChanged(false);
    }

    if(!account_node.isNull()) account_node = FileNodeVisitor();
    if(!server_node.isNull()) server_node = FileNodeVisitor();
    if(FileNodeVisitor node = db.getRoot()("active_session"); node.getElementCount())
      node.setVariable(varr{});

    client.disconnect();

    emit connectionStateChanged(false);
    emit userListChanged(QVariant());
    emit serverInfoChanged(QVariant());

    return true;
  } else return false;
}

bool API::authenticate(QString login, QString password) {
  if(!isConnectionSecured()) {
    emit recivedError("Connection isn't secured!");
    return false;
  }

  BufferArray login_bfr = login.toStdU16String();

  private_aes256_key = Security::createAES256Key(BufferArray(password.toStdU16String()).toByteArray());

  if(auto account = server_node[{"account_list", login_bfr}]; account.isNull()) {
    server_node["account_list"].setVariable(login_bfr, vobj{});
  } else account.setVariable(vobj{});
  db["active_session"].setVariable(1, login_bfr);

  client << encrypt(vobj{
                     {"act", ui8(ClientAction::authentication)},
                     {"login", login_bfr},
                     {"password", BufferArray(Security::getHashOf(BufferArray(password.toStdU16String()).toByteArray()))}
                   });

  return true;
}

bool API::registerate(QString login, QString password, QString email) {
  if(!isConnectionSecured()) {
    emit recivedError("Connection isn't secured!");
    return false;
  }

  BufferArray login_bfr = login.toStdU16String();

  if(account_ecdh_key_pair) Security::freeKey(account_ecdh_key_pair);
  account_ecdh_key_pair = Security::genKey();
  private_aes256_key = Security::createAES256Key(BufferArray(password.toStdU16String()).toByteArray());

  server_node["account_list"].setVariable(login_bfr, vobj{});
  db["active_session"].setVariable(1, login_bfr);

  client << encrypt(vobj{
                       {"act", ui8(ClientAction::registration)},
                       {"login", login.toStdU16String()},
                       {"password", BufferArray(Security::getHashOf(BufferArray(password.toStdU16String()).toByteArray()))},
                       {"email", email.toStdString()},
                       {"key", vobj{
                          {"pub", BufferArray(Security::extractPublicKey(account_ecdh_key_pair))},
                          {"enc_priv", BufferArray(Security::encrypt(Security::extractPrivateKey(account_ecdh_key_pair), private_aes256_key))}
                        }}
                     });

  return true;
}

void API::sendPost(QVariant data) {
  FileNodeVisitor node = db["session"];
  if(!node.contains("login") || !node.contains("uuid") || !node.contains("key")) return;

  binom::Array post_data;
  for(QVariant element : data.toList()) {
    QVariantMap element_map = element.toMap();
    QString type = element_map["type"].toString();
    if (type == "text" || type == "title") {
      post_data.pushBack(vobj{
                           {"type","text/plain"},
                           {"data",element_map["data"].toString().toStdU16String()}
                         });
      continue;
    } elif (type == "file") {
      QString url = QUrl(element_map["data"].toString()).toLocalFile();
      if(!QFile::exists(url)) {
        emit recivedError(QString("File with path \"") + url + "\" isn't exist");
        continue;
      }
      QFile file(url);
      file.open(QIODevice::ReadOnly);
      if(!file.isOpen()) {
        emit recivedError(QString("File with path \"") + url + "\" isn't open");
        continue;
      }
      QByteArray file_data = file.readAll();
      post_data.pushBack(vobj{
                           {"type",element_map["mime-type"].toString().toStdU16String()},
                           {"data", BufferArray(ValType::byte, file_data.data(), file_data.length())}
                         });
      continue;
    }
  }

  client << auth(vobj{
                   {"act", ui8(ClientAction::request)},
                   {"request_type", ui8(RequestCode::publish_post)},
                   {"content", post_data},
                   {"is_public", false}
                });
}
