#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <dirent.h>
#include "dowa/dowa.h"

#include <curl/curl.h>
#include "third_party/raylib/include/raylib.h"
#define RAYGUI_IMPLEMENTATION
#include "third_party/raylib/include/raygui.h"

#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 780
#define TEXT_SIZE 10
#define LINE_HEIGHT 15
#define GENERIC_PADDING 15

#define SIDEBAR_WIDTH 200
#define SIDEBAR_PADDING_GENERAL 5
#define SIDEBAR_AREA_PADDING_X 10
#define SIDEBAR_AREA_PADDING_Y 10
#define SIDEBAR_REFERSH_BUTTON_WIDTH 90
#define SIDEBAR_REFERSH_BUTTON_HEIGHT 20
#define SIDEBAR_HISTORY_ITEM_HEIGHT 45

#define URL_INPUT_HEIGHT 40

#define TAB_LEN 3
#define METHOD_BUTTON_WIDTH 100
#define METHOD_BUTTON_HEIGHT 40
#define SEND_BUTTON_WIDTH 100
#define SEND_BUTTON_HEIGHT 40

#define JSON_INPUT_BUFFER_LEN 8192
#define HEADER_INPUT_BUFFER_LEN 4096
#define PARAM_INPUT_BUFFER_LEN 4096
#define MAX_HISTORY_ITEMS 100

// Structure to hold response data
typedef struct {
  char *data;
  size_t size;
} ResponseBuffer;

// Structure to hold history item
typedef struct {
  char filename[256];
  char displayName[128];
  char method[16];
  time_t timestamp;
} HistoryItem;

typedef enum {
  ActiveTab_JSON = 0,
  ActiveTab_Headers, 
  ActiveTab_Params,
} ActiveTab;

static size_t Postdog_Curl_Callback(void *contents, size_t size, size_t nmemb, void *userp)
{
  size_t real_size = size * nmemb;
  ResponseBuffer *buf = (ResponseBuffer *)userp;

  char *ptr = realloc(buf->data, buf->size + real_size + 1);
  if (ptr == NULL)
  {
    printf("Not enough memory for response\n");
    return 0;
  }

  buf->data = ptr;
  memcpy(&(buf->data[buf->size]), contents, real_size);
  buf->size += real_size;
  buf->data[buf->size] = 0;

  return real_size;
}

int PostDog_Make_HttpRequest(const char *url, const char *method, const char *headers,
                    const char *body, char *response, size_t responseSize)
{
  CURL *curl;
  CURLcode res;
  ResponseBuffer buffer = { .data = malloc(1), .size = 0 };

  if (buffer.data == NULL)
  {
    snprintf(response, responseSize, "Error: Failed to allocate memory");
    return -1;
  }
  buffer.data[0] = '\0';

  curl_global_init(CURL_GLOBAL_DEFAULT);
  curl = curl_easy_init();

  if (curl)
  {
    struct curl_slist *headerList = NULL;

    // Set URL
    curl_easy_setopt(curl, CURLOPT_URL, url);

    // Set HTTP method
    if (strcmp(method, "POST") == 0)
    {
      curl_easy_setopt(curl, CURLOPT_POST, 1L);
      if (body && strlen(body) > 0) {
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
      }
    } 
    else if (strcmp(method, "PUT") == 0)
    {
      curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
      if (body && strlen(body) > 0) {
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
      }
    }
    else if (strcmp(method, "DELETE") == 0)
    {
      curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
    }
    // Default is GET

    // Parse and add headers
    if (headers && strlen(headers) > 0)
    {
      char *headersCopy = strdup(headers);
      char *line = strtok(headersCopy, "\n");
      while (line != NULL) {
        // Trim whitespace
        while (*line == ' ' || *line == '\t') line++;
        if (strlen(line) > 0) {
          headerList = curl_slist_append(headerList, line);
        }
        line = strtok(NULL, "\n");
      }
      curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList);
      free(headersCopy);
    }

    // Set write callback
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Postdog_Curl_Callback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buffer);

    // Follow redirects
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

    // Set timeout
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);

    // Perform request
    res = curl_easy_perform(curl);

    if (res != CURLE_OK)
      snprintf(response, responseSize, "Error: %s\n", curl_easy_strerror(res));
    else
    {
      long response_code;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);

      snprintf(response, responseSize, "HTTP Status: %ld\n\n%s",
               response_code, buffer.data ? buffer.data : "");
    }

    // Cleanup
    if (headerList) curl_slist_free_all(headerList);
    curl_easy_cleanup(curl);
  } else {
    snprintf(response, responseSize, "Error: Failed to initialize curl");
  }

  free(buffer.data);
  curl_global_cleanup();

  return 0;
}

typedef struct {
  Rectangle rectangle;
  char *label;
} TabItem;

int main()
{
  // -- initizlied --//
  InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "PostDog");
  SetWindowState(FLAG_WINDOW_RESIZABLE);
  SetTargetFPS(60);

  Dowa_Arena *arena = Dowa_Arena_Create(1024 * 1025 * 10);

  // -- Starting pos ---//
  float side_bar_x = 10;
  float side_bar_y = 10;

  Rectangle history_sidebar = { .x = side_bar_x, .y = side_bar_y, .width = 0, .height = 0 };

  Rectangle url_area = { 0 };
  Rectangle textBounds = { 0 };
  Rectangle url_input_bounds = { 0 };
  Rectangle url_text_bounds = { 0 };
  Rectangle url_enter_button = { 0 };

  char *input_text = (char *)Dowa_Arena_Allocate(arena, 1024 * 4);
  int sendRequest;

  Rectangle input_area = { 0 };
  Rectangle input_tab = { 0 };
  TabItem input_tab_items[4] = {
    {
      .rectangle={0}, .label="body"
    },
    {
      .rectangle={0}, .label="header"
    },
    {
      .rectangle={0}, .label="foo"
    },
    {
      .rectangle={0}, .label="bar"
    },
  };
  Rectangle input_body = { 0 };

  Rectangle result_area = { 0 };
  Rectangle result_body = { 0 };

  // General styling.
  int padding = 10; // TODO make it % based?


  while (!WindowShouldClose())
  {
    int screen_width = GetScreenWidth();
    int screen_height = GetScreenHeight();

    history_sidebar.width = screen_width * 0.15;
    history_sidebar.height = screen_width - 10;

    // -- URL Area --//
    url_area.x = (side_bar_x + history_sidebar.width);
    url_area.y = (side_bar_y);
    url_area.width = (screen_width - history_sidebar.width) * 0.9;
    url_area.height = (screen_height) * 0.1;

    url_text_bounds.x = url_area.x + padding;
    url_text_bounds.y = (url_area.height) / 2;
    url_text_bounds.width = 7 * (TEXT_SIZE / 2);
    url_text_bounds.height = TEXT_SIZE * 2;

    url_input_bounds.x = url_text_bounds.x + url_text_bounds.width + padding;
    url_input_bounds.y = (url_area.height) / 2;
    url_input_bounds.width = (url_area.width - padding) * 0.7;
    url_input_bounds.height = TEXT_SIZE * 2;

    url_enter_button.x = url_input_bounds.x + url_input_bounds.width + padding;
    url_enter_button.y = (url_area.height) / 2;
    url_enter_button.width = (url_area.width - padding) * 0.1;
    url_enter_button.height = TEXT_SIZE * 2;

    // -- Input Area --//
    input_area.x = (side_bar_x + history_sidebar.width);
    input_area.y = (side_bar_y + url_area.height);
    input_area.width = url_area.width * 0.5;
    input_area.height = screen_height - url_area.height;

    input_tab.x = (side_bar_x + history_sidebar.width) + padding;
    input_tab.y = (side_bar_y + url_area.height) + padding;
    input_tab.width = url_area.width * 0.49 - padding;
    input_tab.height = input_area.height * 0.1;
    for (int pos = 0; pos < 4; pos++)
    {
      input_tab_items[pos].rectangle = input_tab;
      input_tab_items[pos].rectangle.x = input_tab.x + (pos * input_tab.width / 4);
      input_tab_items[pos].rectangle.width = input_tab.width / 4;
    }

    input_body.x = input_tab.x;
    input_body.y = input_tab.y + input_tab.height;
    input_body.width = url_area.width * 0.49 - padding;
    input_body.height = input_area.height - input_tab.height - padding;

    // -- Result Area --//
    result_area.x = (input_area.x + input_area.width);
    result_area.y = (side_bar_y + url_area.height);
    result_area.width = url_area.width * 0.49;
    result_area.height = screen_height - url_area.height;

    result_body.x = result_area.x + padding;
    result_body.y = result_area.y + input_tab.height + padding;
    result_body.width = url_area.width * 0.49 - padding;
    result_body.height = result_area.height - input_tab.height - padding;

    BeginDrawing();
      ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));

      // Sidebar Rect
      DrawRectangleRec(history_sidebar, Fade(GRAY, 0.1f));

      // URL area Rect
      GuiDrawText("URL: ", url_text_bounds, TEXT_ALIGN_CENTER, RED); 
      DrawRectangleRec(url_area, Fade(RED, 0.1f));
      GuiTextBox(url_input_bounds, input_text, 1024 * 4, true);
      sendRequest = GuiButton(url_enter_button, "ENTER");

      // Input Tabs Rect
      DrawRectangleRec(input_area, Fade(BLUE, 0.1f));
      DrawRectangleRec(input_tab,  Fade(DARKBLUE, 0.1f));
      for (int pos = 0; pos < 4; pos++)
      {
        JUNE_GuiButton(input_tab_items[pos].rectangle, input_tab_items[pos].label, 0, Fade(DARKBLUE, 0.1f)); 
      }
      JUNE_GuiTextBox(input_body, input_text, 1024 * 4, true);

      // Result Rect
      DrawRectangleRec(result_area, Fade(GREEN, 0.1f));
      DrawRectangleRec(result_body, Fade(DARKGREEN, 0.1f));
    EndDrawing();
  }
  CloseWindow();
  return 0;
}
