#include <sys/epoll.h>
#include "seobeo/seobeo.h"


void  *Seobeo_Web_Edge_Worker(void *vargs)
{
  WorkerArgs *args = vargs;
  struct epoll_event events[64];
  while (1) {
    int n = epoll_wait(args->evfd, events, 64, -1);
    if (n < 0) continue;
    for (int i = 0; i < n; i++) {
      Seobeo_PHandle h = events[i].data.ptr;
      if (h == args->srv) {
        // new connection
        Seobeo_PHandle cli =
          Seobeo_Stream_Handle_Accept(args->srv);
        if (!cli) continue;
        struct epoll_event ev = {
          .events   = EPOLLIN,
          .data.ptr = cli
        };
        epoll_ctl(args->evfd, EPOLL_CTL_ADD,
                  cli->socket, &ev);
      } else {
        Seobeo_Web_HandleClientRequest(h, args->cache); // This frees
        epoll_ctl(args->evfd, EPOLL_CTL_DEL,
                  h->socket, NULL);
      }
    }
  }
  return NULL;
}

void  Seobeo_Web_Edge(
    Seobeo_PHandle p_server_handle,
    int            thread_count,
    Dowa_PHashMap   p_html_cache)
{
  int epfd = epoll_create1(0);
  struct epoll_event ev = {
    .events   = EPOLLIN | EPOLLONESHOT,
    .data.ptr = p_server_handle
  };
  epoll_ctl(epfd, EPOLL_CTL_ADD,
            p_server_handle->socket, &ev);

  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setstacksize(&attr, 100 * 1024 * 1024); // 100 MB

  pthread_t  threads[thread_count];
  for (int i = 0; i < thread_count; i++)
  {
    WorkerArgs *args = malloc(sizeof(WorkerArgs));
    *args = (WorkerArgs){ p_server_handle, p_html_cache, epfd };

    pthread_create(&threads[i], NULL, Seobeo_Web_Edge_Worker, args);
  }
  for (int i = 0; i < thread_count; i++)
  {
    pthread_join(threads[i], NULL);
  }
  return;
}
