#include <sys/un.h>
#include <sys/socket.h>
#include <zconf.h>

#include "include/communication/UnixSocketServer.hpp"
#include "include/communication/MessageProcessor.hpp"

UnixSocketServer::UnixSocketServer() {
  server_thread = std::thread(&UnixSocketServer::server_loop, this);
  server_thread.detach();
}

[[noreturn]] void UnixSocketServer::server_loop() {
  struct sockaddr_un socket_address;
  int socket_file_descriptor = socket(AF_UNIX, SOCK_STREAM, 0);
  remove(SOCKET_PATH);

  memset(&socket_address, 0, sizeof(struct sockaddr_un));
  socket_address.sun_family = AF_UNIX;
  strncpy(socket_address.sun_path, SOCKET_PATH, sizeof(socket_address.sun_path) - 1);

  if (bind(socket_file_descriptor, (struct sockaddr *) &socket_address, sizeof(struct sockaddr_un)) == -1) {
    exit(-1);
  }

  if (listen(socket_file_descriptor, 1) == -1) {
    exit(-2);
  }

  char read_buffer[SOCKET_BUFFER_SIZE];
  char write_buffer[SOCKET_BUFFER_SIZE];
  for (;;) {
    int client_file_descriptor = accept(socket_file_descriptor, NULL, NULL);

    read(client_file_descriptor, read_buffer, 1);
    uint8_t message_size = read_buffer[0];

    read(client_file_descriptor, read_buffer, read_buffer[0]);
    std::string string_message;
    for (int i{}; i < message_size; i++) {
      string_message += read_buffer[i];
    }

    auto response = MessageProcessor::process_message(string_message);
    uint8_t response_size = response->ByteSizeLong();
    write_buffer[0] = response_size;
    write(client_file_descriptor, write_buffer, 1);

    response->SerializeToArray(write_buffer, SOCKET_BUFFER_SIZE);
    write(client_file_descriptor, write_buffer, response_size);

    close(client_file_descriptor);
  }
}