#include "core/profile.h"
#include "db/database.h"
#include "settings/flags.h"
#include "ui/newtab.h"
#include <errno.h>
#include <gio/gio.h>
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <webkit2/webkit2.h>

extern FlagsManager *get_global_flags_manager(void);

static void handle_leaf_scheme_request(WebKitURISchemeRequest *request,
                                       gpointer user_data) {
  Profile *profile = (Profile *)user_data;
  const gchar *uri = webkit_uri_scheme_request_get_uri(request);
  char *html_content = NULL;
  gsize content_len = 0;

  if (g_str_has_prefix(uri, "leaf://newtab") ||
      g_strcmp0(uri, "leaf:newtab") == 0) {
    html_content = newtab_get_html(profile);
  } else if (g_str_has_prefix(uri, "leaf://flags") ||
             g_strcmp0(uri, "leaf:flags") == 0) {
    FlagsManager *fm = get_global_flags_manager();
    if (fm) {
      html_content = flags_manager_get_flags_html(fm);
    } else {
      html_content = g_strdup("<html><body><h1>Error</h1><p>Flags manager not "
                              "ready</p></body></html>");
    }
  } else {
    html_content =
        g_strdup("<html><body><h1>Error</h1><p>Unknown page</p></body></html>");
  }

  if (html_content) {
    content_len = strlen(html_content);
    GInputStream *stream =
        g_memory_input_stream_new_from_data(html_content, content_len, g_free);
    webkit_uri_scheme_request_finish(request, stream, content_len, "text/html");
    g_object_unref(stream);
  } else {
    GError *error =
        g_error_new(WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_FAILED,
                    "Failed to generate content");
    webkit_uri_scheme_request_finish_error(request, error);
    g_error_free(error);
  }
}

#define PROFILE_BASE_DIR ".local/share/LeafWeb/profiles"

/**
 * Create directory recursively
 */
static int create_directory(const char *path) {
  char tmp[512];
  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;
      if (mkdir(tmp, 0755) != 0 && errno != EEXIST) {
        return -1;
      }
      *p = '/';
    }
  }
  if (mkdir(tmp, 0755) != 0 && errno != EEXIST) {
    return -1;
  }
  return 0;
}

/**
 * Get the base profile directory path
 */
static char *get_profile_base_path(void) {
  const char *home = getenv("HOME");
  if (!home) {
    return NULL;
  }

  char *path = g_build_filename(home, PROFILE_BASE_DIR, NULL);
  return path;
}

/**
 * Get the profile directory path for a specific profile
 */
static char *get_profile_path(const char *profile_name) {
  char *base = get_profile_base_path();
  if (!base) {
    return NULL;
  }

  char *path = g_build_filename(base, profile_name, NULL);
  g_free(base);
  return path;
}

/**
 * Create profile directory structure
 */
static int create_profile_structure(const char *profile_path) {
  // Create main profile directory
  if (create_directory(profile_path) != 0) {
    return -1;
  }

  // Create subdirectories
  char path[512];

  snprintf(path, sizeof(path), "%s/cookies", profile_path);
  if (create_directory(path) != 0)
    return -1;

  snprintf(path, sizeof(path), "%s/local_storage", profile_path);
  if (create_directory(path) != 0)
    return -1;

  snprintf(path, sizeof(path), "%s/extensions", profile_path);
  if (create_directory(path) != 0)
    return -1;

  return 0;
}

Profile *load_profile(const char *profile_name) {
  if (!profile_name) {
    return NULL;
  }

  // Get profile path
  char *profile_path = get_profile_path(profile_name);
  if (!profile_path) {
    return NULL;
  }

  // Create profile structure if it doesn't exist
  if (create_profile_structure(profile_path) != 0) {
    g_free(profile_path);
    return NULL;
  }

  // Allocate profile structure
  Profile *profile = g_malloc0(sizeof(Profile));
  profile->name = g_strdup(profile_name);
  profile->base_path = profile_path;

  // Create paths for WebKit data
  char *cache_dir = g_build_filename(profile_path, "cache", NULL);
  char *data_dir = g_build_filename(profile_path, "local_storage", NULL);

  // Create WebKitWebsiteDataManager
  profile->data_manager = webkit_website_data_manager_new(
      "base-cache-directory", cache_dir, "base-data-directory", data_dir, NULL);

  // Create WebKitWebContext with the data manager
  profile->context =
      webkit_web_context_new_with_website_data_manager(profile->data_manager);

  // Register 'leaf' scheme as secure/local
  WebKitSecurityManager *security_manager =
      webkit_web_context_get_security_manager(profile->context);
  webkit_security_manager_register_uri_scheme_as_secure(security_manager,
                                                        "leaf");
  webkit_security_manager_register_uri_scheme_as_local(security_manager,
                                                       "leaf");
  webkit_security_manager_register_uri_scheme_as_cors_enabled(security_manager,
                                                              "leaf");

  // Register URI scheme handler
  webkit_web_context_register_uri_scheme(
      profile->context, "leaf",
      (WebKitURISchemeRequestCallback)handle_leaf_scheme_request, profile,
      NULL);

  g_free(cache_dir);
  g_free(data_dir);

  // Initialize settings database
  char *db_path = g_build_filename(profile_path, "settings.db", NULL);
  profile->db = settings_init(db_path);
  g_free(db_path);

  if (!profile->db) {
    fprintf(stderr, "Warning: Failed to initialize settings database\n");
  }

  return profile;
}

Profile *init_default_profile(void) { return load_profile("default"); }

Profile *create_private_profile(void) {
  Profile *profile = g_new0(Profile, 1);
  profile->name = g_strdup("Incognito");
  profile->base_path = NULL; // No path for private profile
  profile->is_private = TRUE;

  // Ephemeral data manager
  profile->data_manager = webkit_website_data_manager_new_ephemeral();

  // Web Context
  profile->context =
      webkit_web_context_new_with_website_data_manager(profile->data_manager);

  // No database for private profile (or in-memory if needed, but NULL is safer
  // for "no save")
  profile->db = NULL;

  return profile;
}

void free_profile(Profile *profile) {
  if (!profile) {
    return;
  }

  g_free(profile->name);
  g_free(profile->base_path);

  if (profile->context) {
    g_object_unref(profile->context);
  }
  if (profile->data_manager) {
    g_object_unref(profile->data_manager);
  }
  if (profile->db) {
    settings_close(profile->db);
  }

  g_free(profile);
}
