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

#define MAX_RESPONSE_SIZE (1024 * 1024)

// Helper: Convert URL path to filename
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: Generate HTTP GET request
static int generate_http_get(char *buffer, size_t size, const char *path, const char *host)
{
  return snprintf(
    buffer, size,
    "GET %s HTTP/1.1\r\n"
    "Host: %s\r\n"
    "Connection: close\r\n"
    "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
    "User-Agent: SeobeoSnapshotCreator/1.0\r\n"
    "\r\n",
    path, host
  );
}

// Helper: Read full HTTP response
static char* read_full_response(Seobeo_Handle *client, size_t *len_out)
{
  char *response = malloc(MAX_RESPONSE_SIZE);
  if (!response)
  {
    return NULL;
  }

  size_t total = 0;
  int attempts = 0;
  const int max_attempts = 100;

  while (attempts++ < max_attempts && total < MAX_RESPONSE_SIZE - 1)
  {
    int n = Seobeo_Handle_Read(client);

    if (n > 0)
    {
      size_t to_copy = client->read_buffer_len;
      if (total + to_copy > MAX_RESPONSE_SIZE - 1)
      {
        to_copy = MAX_RESPONSE_SIZE - 1 - total;
      }

      memcpy(response + total, client->read_buffer, to_copy);
      total += to_copy;
      Seobeo_Handle_Consume(client, (uint32)to_copy);
    }
    else if (n == -2)
    {
      break;
    }
    else if (n == 0)
    {
      usleep(10000);
      continue;
    }
    else
    {
      free(response);
      return NULL;
    }
  }

  response[total] = '\0';
  *len_out = total;
  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);

  // Connect to server
  Seobeo_Handle *client = Seobeo_Stream_Handle_Client_Create(config->host, config->port, FALSE);
  if (!client || client->socket < 0)
  {
    fprintf(stderr, "  ✗ Failed to connect to %s:%s\n", config->host, config->port);
    if (client)
    {
      Seobeo_Handle_Destroy(client);
    }
    return -1;
  }

  // Send GET request
  char request[4096];
  int req_len = generate_http_get(request, sizeof(request), config->path, config->host);
  Seobeo_Handle_Queue(client, (uint8*)request, (uint32)req_len);

  if (Seobeo_Handle_Flush(client) < 0)
  {
    fprintf(stderr, "  ✗ Failed to send request\n");
    Seobeo_Handle_Destroy(client);
    return -1;
  }

  // Read response
  size_t response_len = 0;
  char *response = read_full_response(client, &response_len);
  Seobeo_Handle_Destroy(client);

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

  // Parse status code
  int status = -1;
  const char *status_line = strstr(response, "HTTP/1.1 ");
  if (!status_line)
  {
    status_line = strstr(response, "HTTP/1.0 ");
  }
  if (status_line)
  {
    sscanf(status_line + 9, "%d", &status);
  }

  if (status != config->expected_status)
  {
    fprintf(stderr, "  ✗ Status mismatch: expected %d, got %d\n",
            config->expected_status, status);
    free(response);
    return -1;
  }

  printf("  ✓ Status: %d\n", status);

  // 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;
}
