#include "seobeo/snapshot_creator.h"
#include "seobeo/seobeo_internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

static void path_to_filename(const char *path, char *filename, size_t max_len)
{
  if (strcmp(path, "/") == 0)
  {
    snprintf(filename, max_len, "root.snapshot");
    return;
  }

  const char *p = path;
  if (*p == '/')
    p++;

  char *out = filename;
  size_t remaining = max_len - 1;

  while (*p && remaining > 0)
  {
    if (*p == '/')
    {
      *out++ = '_';
      remaining--;
    }
    else
    {
      *out++ = *p;
      remaining--;
    }
    p++;
  }

  snprintf(out, remaining, ".snapshot");
}

// Helper: Create directory recursively
static int create_directory(const char *path)
{
  char tmp[1024];
  char *p = NULL;
  size_t len;

  snprintf(tmp, sizeof(tmp), "%s", path);
  len = strlen(tmp);
  if (tmp[len - 1] == '/')
  {
    tmp[len - 1] = 0;
  }

  for (p = tmp + 1; *p; p++)
  {
    if (*p == '/')
    {
      *p = 0;
      mkdir(tmp, 0755);
      *p = '/';
    }
  }
  return mkdir(tmp, 0755);
}

// Helper: Build full HTTP response from Seobeo_Client_Response
static char* build_full_response(Seobeo_Client_Response *p_resp, size_t *len_out)
{
  if (!p_resp)
    return NULL;

  // Calculate total response size
  size_t status_line_len = 100; // "HTTP/1.1 200 OK\r\n"
  size_t headers_len = 0;
  size_t body_len = p_resp->body_length;

  // Estimate header size
  if (p_resp->headers)
  {
    size_t header_count = Dowa_Array_Length(p_resp->headers);
    for (size_t i = 0; i < header_count; i++)
    {
      headers_len += strlen(p_resp->headers[i].key) + strlen(p_resp->headers[i].value) + 4; // ": " + "\r\n"
    }
  }

  size_t total_size = status_line_len + headers_len + 2 + body_len + 1; // +2 for "\r\n", +1 for null terminator
  char *response = malloc(total_size);
  if (!response)
    return NULL;

  // Build status line
  int offset = snprintf(response, total_size, "HTTP/1.1 %d %s\r\n",
                        p_resp->status_code,
                        p_resp->status_text ? p_resp->status_text : "OK");

  // Add headers
  if (p_resp->headers)
  {
    size_t header_count = Dowa_Array_Length(p_resp->headers);
    for (size_t i = 0; i < header_count; i++)
    {
      offset += snprintf(response + offset, total_size - offset, "%s: %s\r\n",
                        p_resp->headers[i].key,
                        p_resp->headers[i].value);
    }
  }

  // End of headers
  offset += snprintf(response + offset, total_size - offset, "\r\n");

  // Add body
  if (p_resp->body && body_len > 0)
  {
    memcpy(response + offset, p_resp->body, body_len);
    offset += body_len;
  }

  response[offset] = '\0';
  *len_out = offset;
  return response;
}

// Helper: Write snapshot to file
static int write_snapshot(const char *filepath, const char *data, size_t size)
{
  // Create directory if needed
  char dir_copy[1024];
  snprintf(dir_copy, sizeof(dir_copy), "%s", filepath);

  char *last_slash = strrchr(dir_copy, '/');
  if (last_slash)
  {
    *last_slash = '\0';
    create_directory(dir_copy);
  }

  FILE *f = fopen(filepath, "wb");
  if (!f)
  {
    perror("fopen");
    return -1;
  }

  size_t written = fwrite(data, 1, size, f);
  fclose(f);

  return (written == size) ? 0 : -1;
}

int Seobeo_Snapshot_Create(const SnapshotConfig *config)
{
  if (!config || !config->path || !config->snapshot_dir || !config->host || !config->port)
  {
    fprintf(stderr, "Invalid snapshot config\n");
    return -1;
  }

  printf("Creating snapshot: %s (expecting %d)\n", config->path, config->expected_status);

  // Build URL
  char url[2048];
  snprintf(url, sizeof(url), "http://%s:%s%s", config->host, config->port, config->path);

  // Create HTTP request
  Seobeo_Client_Request *p_req = Seobeo_Client_Request_Create(url);
  if (!p_req)
  {
    fprintf(stderr, "  ✗ Failed to create request for %s\n", url);
    return -1;
  }

  // Execute request
  Seobeo_Client_Response *p_resp = Seobeo_Client_Request_Execute(p_req);
  if (!p_resp)
  {
    fprintf(stderr, "  ✗ Failed to get response\n");
    Seobeo_Client_Request_Destroy(p_req);
    return -1;
  }

  // Check status code
  if (p_resp->status_code != config->expected_status)
  {
    fprintf(stderr, "  ✗ Status mismatch: expected %d, got %d\n",
            config->expected_status, p_resp->status_code);
    Seobeo_Client_Response_Destroy(p_resp);
    Seobeo_Client_Request_Destroy(p_req);
    return -1;
  }

  printf("  ✓ Status: %d\n", p_resp->status_code);

  // Build full HTTP response
  size_t response_len = 0;
  char *response = build_full_response(p_resp, &response_len);

  Seobeo_Client_Response_Destroy(p_resp);
  Seobeo_Client_Request_Destroy(p_req);

  if (!response || response_len == 0)
  {
    fprintf(stderr, "  ✗ Failed to build response\n");
    if (response)
      free(response);
    return -1;
  }

  // Generate snapshot filename
  char filename[256];
  path_to_filename(config->path, filename, sizeof(filename));

  char filepath[1024];
  snprintf(filepath, sizeof(filepath), "%s/%s", config->snapshot_dir, filename);

  // Write snapshot
  if (write_snapshot(filepath, response, response_len) == 0)
  {
    printf("  ✓ Snapshot saved: %s (%zu bytes)\n", filepath, response_len);
    free(response);
    return 0;
  }
  else
  {
    fprintf(stderr, "  ✗ Failed to write snapshot: %s\n", filepath);
    free(response);
    return -1;
  }
}

int Seobeo_Snapshots_Create_Batch(const SnapshotConfig configs[], int count)
{
  int failed = 0;
  int passed = 0;

  for (int i = 0; i < count; i++)
  {
    if (Seobeo_Snapshot_Create(&configs[i]) == 0)
    {
      passed++;
    }
    else
    {
      failed++;
    }
    printf("\n");
  }

  printf("=== Summary ===\n");
  printf("Created: %d\n", passed);
  printf("Failed: %d\n", failed);

  return (failed == 0) ? 0 : -1;
}
