#pragma once

#include <esp_http_server.h>
#include <functional>
#include "Dtypes.h"
#include "Logger.h"

constexpr int MAX_URI_HANDLERS = 25;

esp_err_t rawCallback(httpd_req_t *req);

class EspHttp
{
public:
  using Callback = std::function<void(httpd_req_t *)>;

  EspHttp(int port = 80) : server_(0), nextFreeHandler_(0)
  {
    config_ = HTTPD_DEFAULT_CONFIG();
    config_.server_port = port;
    config_.max_uri_handlers = MAX_URI_HANDLERS;
    config_.uri_match_fn = httpd_uri_match_wildcard;
  }
  ~EspHttp()
  {
    stop();
  }

  void start()
  {
    if (httpd_start(&server_, &config_) != ESP_OK)
      assert_msg(false, "HTTPD server didn't start");
  }

  void stop()
  {
    if (server_)
      httpd_stop(server_);
    server_ = 0;
  }

  void on(const char *uri, httpd_method_t method, Callback cb)
  {
    if (nextFreeHandler_ == MAX_URI_HANDLERS)
    {
      assert_msg(nextFreeHandler_ < MAX_URI_HANDLERS, "Too many handlers - increase MAX_URI_HANDLERS");
      return;
    }
    handlerCallbacks_[nextFreeHandler_] = cb;

    httpd_uri_t uri_endpoint_cfg = {
        .uri = uri,
        .method = method,
        .handler = rawCallback,
        .user_ctx = (void *)(&handlerCallbacks_[nextFreeHandler_])};
    if (httpd_register_uri_handler(server_, &uri_endpoint_cfg) != ESP_OK)
      LOG_WARNING("Failed to register url handler");
    ++nextFreeHandler_;
  }

  void write(const char *data, ssize_t length);

private:
  httpd_config_t config_;
  httpd_handle_t server_;
  int nextFreeHandler_;
  Callback handlerCallbacks_[MAX_URI_HANDLERS];
};

esp_err_t rawCallback(httpd_req_t *req);

int getUrlQueryParameter(httpd_req_t *req, const char *name, int defaultValue);