#include "ui/tabs.h"
#include "db/database.h"
#include "extensions/adblock/adblock.h"
#include "extensions/adblock/yt_adblock.h"
#include "settings/flags.h"
#include "ui/menu.h"
#include "ui/toolbar.h"
#include "web/navigation.h"
#include <string.h>

typedef struct {
  GtkWidget *tab_widget; // The box in the headerbar
  GtkWidget *label;
  GtkWidget *close_btn;
  GtkWidget *webview;
  char *title;
} Tab;

struct _TabManager {
  GtkWindow *window;
  Profile *profile;

  GtkWidget *header_box;     // Container for tabs in headerbar
  GtkWidget *tabs_container; // Box inside scrolled window
  GtkWidget *content_stack;  // Stack for webviews

  GtkEntry *url_entry; // Reference to URL bar in toolbar

  GList *tabs;        // List of Tab*
  GList *closed_tabs; // List of char* (URLs)
  Tab *current_tab;
};

static void update_tab_title(Tab *tab);
static void on_tab_close_clicked(GtkButton *button, Tab *tab);
static gboolean on_tab_clicked(GtkWidget *widget, GdkEventButton *event,
                               Tab *tab);
static void on_new_tab_clicked(GtkButton *button, TabManager *manager);
static void setup_dnd(Tab *tab);
static void on_flag_changed_message(WebKitUserContentManager *manager,
                                    WebKitJavascriptResult *js_result,
                                    gpointer user_data);
void tab_manager_close_tab(TabManager *manager, Tab *tab);
void tab_manager_duplicate_tab(TabManager *manager, Tab *tab);

static Tab *create_tab(TabManager *manager, const char *url);

// Declare external getter from main.c
extern AdblockManager *get_global_adblock_manager(void);
extern YTAdblockManager *get_global_yt_adblock_manager(void);
extern FlagsManager *get_global_flags_manager(void);

// Message handler for flag changes from JavaScript
static void on_flag_changed_message(WebKitUserContentManager *manager,
                                    WebKitJavascriptResult *js_result,
                                    gpointer user_data) {
  JSCValue *value = webkit_javascript_result_get_js_value(js_result);

  if (!value || !jsc_value_is_object(value)) {
    return;
  }

  JSCValue *name_val = jsc_value_object_get_property(value, "name");
  JSCValue *value_val = jsc_value_object_get_property(value, "value");

  if (!name_val || !value_val) {
    return;
  }

  if (jsc_value_is_string(name_val) && jsc_value_is_string(value_val)) {
    char *flag_name = jsc_value_to_string(name_val);
    char *flag_value = jsc_value_to_string(value_val);

    if (flag_name && flag_value) {
      FlagsManager *flags_mgr = get_global_flags_manager();
      if (flags_mgr) {
        if (flags_manager_set_value(flags_mgr, flag_name, flag_value)) {
          g_print("✓ Saved flag: %s = %s\n", flag_name, flag_value);
        } else {
          g_warning("Failed to save flag: %s\n", flag_name);
        }
      }
    }

    // JSCValue strings must be freed
    if (flag_name)
      g_free(flag_name);
    if (flag_value)
      g_free(flag_value);
  }

  // Note: JSCValue objects from jsc_value_object_get_property are autoreleased
  // Do not unref them manually
}

static void update_tab_title(Tab *tab) {
  const char *title = webkit_web_view_get_title(WEBKIT_WEB_VIEW(tab->webview));
  if (!title)
    title = "New Tab";
  gtk_label_set_text(GTK_LABEL(tab->label), title);

  // Truncate if too long (ellipsize handled by label properties)
}

static void on_title_changed(WebKitWebView *webview, GParamSpec *pspec,
                             Tab *tab) {
  update_tab_title(tab);
}

static gboolean on_context_menu(WebKitWebView *webview,
                                WebKitContextMenu *context_menu,
                                GdkEvent *event,
                                WebKitHitTestResult *hit_test_result,
                                gpointer user_data) {
  // We can clear or append. Let's append our own items for better UX.
  // Or we can rebuild it to be "cleaner". Let's clean it up slightly and add
  // ours.

  // For now, let's keep default and append our special ones if needed,
  // or just rely on default WebKit menu which actually has many of these?
  // User said "It's kinda like a baren land".
  // WebKit2GTK default menu IS usually bare.

  // Let's implement the requested options.
  webkit_context_menu_remove_all(context_menu);

  guint context = webkit_hit_test_result_get_context(hit_test_result);

  // Link options
  if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) {
    const char *link_uri = webkit_hit_test_result_get_link_uri(hit_test_result);

    // Open Link
    // Actually, WebKit has standard actions.
    webkit_context_menu_append(context_menu,
                               webkit_context_menu_item_new_from_stock_action(
                                   WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK));

    // Open in New Tab
    webkit_context_menu_append(
        context_menu, webkit_context_menu_item_new_from_stock_action(
                          WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW));
    // Note: WebKit often calls it "Open in New Window" but the policy handler
    // can redirect to Tab.

    // Create Custom "Open in New Tab" to be sure
    WebKitContextMenuItem *item_new_tab =
        webkit_context_menu_item_new_from_stock_action_with_label(
            WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW,
            "Open in New Tab");
    webkit_context_menu_append(context_menu, item_new_tab);

    // Open in New Window (Actual window)
    // We might need a custom signal for this if we redirect the default one.
    // Let's rely on standard actions first and see if they work.

    // Copy Link Location
    webkit_context_menu_append(
        context_menu, webkit_context_menu_item_new_from_stock_action(
                          WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD));
  }

  // Image options
  if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
    webkit_context_menu_append(
        context_menu, webkit_context_menu_item_new_from_stock_action(
                          WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW));
    webkit_context_menu_append(
        context_menu,
        webkit_context_menu_item_new_from_stock_action(
            WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK)); // Save image
                                                                 // as
    webkit_context_menu_append(
        context_menu, webkit_context_menu_item_new_from_stock_action(
                          WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD));
    webkit_context_menu_append(
        context_menu,
        webkit_context_menu_item_new_from_stock_action(
            WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD));
  }

  // Selection options
  if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION) {
    webkit_context_menu_append(context_menu,
                               webkit_context_menu_item_new_from_stock_action(
                                   WEBKIT_CONTEXT_MENU_ACTION_COPY));
  } else if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) {
    webkit_context_menu_append(context_menu,
                               webkit_context_menu_item_new_from_stock_action(
                                   WEBKIT_CONTEXT_MENU_ACTION_CUT));
    webkit_context_menu_append(context_menu,
                               webkit_context_menu_item_new_from_stock_action(
                                   WEBKIT_CONTEXT_MENU_ACTION_COPY));
    webkit_context_menu_append(context_menu,
                               webkit_context_menu_item_new_from_stock_action(
                                   WEBKIT_CONTEXT_MENU_ACTION_PASTE));
  }

  // Navigation (always available if not editable/selection only?)
  webkit_context_menu_append(context_menu,
                             webkit_context_menu_item_new_separator());
  webkit_context_menu_append(context_menu,
                             webkit_context_menu_item_new_from_stock_action(
                                 WEBKIT_CONTEXT_MENU_ACTION_GO_BACK));
  webkit_context_menu_append(context_menu,
                             webkit_context_menu_item_new_from_stock_action(
                                 WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD));
  webkit_context_menu_append(context_menu,
                             webkit_context_menu_item_new_from_stock_action(
                                 WEBKIT_CONTEXT_MENU_ACTION_RELOAD));

  // Inspect Element
  webkit_context_menu_append(context_menu,
                             webkit_context_menu_item_new_separator());
  webkit_context_menu_append(context_menu,
                             webkit_context_menu_item_new_from_stock_action(
                                 WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT));

  return FALSE;
}

static gboolean on_decide_policy(WebKitWebView *webview,
                                 WebKitPolicyDecision *decision,
                                 WebKitPolicyDecisionType decision_type,
                                 gpointer user_data) {
  TabManager *manager = (TabManager *)user_data;

  switch (decision_type) {
  case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION: {
    WebKitNavigationAction *action =
        webkit_navigation_policy_decision_get_navigation_action(
            WEBKIT_NAVIGATION_POLICY_DECISION(decision));
    WebKitURIRequest *request = webkit_navigation_action_get_request(action);
    const char *uri = webkit_uri_request_get_uri(request);

    // Check for Ctrl+Click (Middle click is usually handled by button check,
    // but modifiers work too)
    guint modifiers = webkit_navigation_action_get_modifiers(action);

    if (modifiers & GDK_CONTROL_MASK) {
      // Open in background tab
      tab_manager_new_tab(manager, uri);
      // Switch back to original tab? tab_manager_new_tab switches to new.
      // We need 'open in background' function or just switch back.
      // Let's implement switch back for now.
      // Actually tab_manager_new_tab switches. We might want a param for
      // "active". For now, let's just let it switch (Ctrl+Click standard is
      // background, Ctrl+Shift is foreground in some, reversed in others). User
      // asked: "Ctrl+Click" > Open link in a new BACKGROUND tab.

      // So we need to create tab but NOT switch.
      // tab_manager_new_tab logic is coupled with switching.
      // Let's modify tab_manager_new_tab? No, let's use internal create_tab
      // logic.

      Tab *tab = create_tab(manager, uri);
      manager->tabs = g_list_append(manager->tabs, tab);
      gtk_box_pack_start(GTK_BOX(manager->tabs_container), tab->tab_widget,
                         FALSE, FALSE, 0);
      gtk_stack_add_named(GTK_STACK(manager->content_stack), tab->webview,
                          g_strdup_printf("%p", tab));
      gtk_widget_show_all(tab->tab_widget);
      gtk_widget_show(tab->webview);

      if (manager->url_entry) {
        navigation_init(WEBKIT_WEB_VIEW(tab->webview), manager->url_entry,
                        manager->profile);
      }

      webkit_web_view_load_uri(WEBKIT_WEB_VIEW(tab->webview), uri);

      // DO NOT SWITCH

      webkit_policy_decision_ignore(decision);
      return TRUE;
    }

    // Default new window behavior -> Open in new foreground tab
    tab_manager_new_tab(manager, uri);
    webkit_policy_decision_ignore(decision);
    return TRUE;
  }
  case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
    // Allow normal navigation
    return FALSE;
  case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
    return FALSE;
  default:
    return FALSE;
  }
}

// Message handler for newtab updates
static void on_newtab_update_message(WebKitUserContentManager *manager,
                                     WebKitJavascriptResult *js_result,
                                     gpointer user_data) {
  Tab *tab = (Tab *)user_data;
  TabManager *tab_manager =
      (TabManager *)g_object_get_data(G_OBJECT(tab->tab_widget), "manager");

  JSCValue *value = webkit_javascript_result_get_js_value(js_result);
  if (!value || !jsc_value_is_object(value))
    return;

  JSCValue *action_val = jsc_value_object_get_property(value, "action");
  if (!action_val || !jsc_value_is_string(action_val))
    return;

  char *action = jsc_value_to_string(action_val);

  if (g_strcmp0(action, "save_shortcuts") == 0) {
    JSCValue *data_val = jsc_value_object_get_property(value, "data");
    if (data_val && jsc_value_is_string(data_val)) {
      char *data = jsc_value_to_string(data_val);
      settings_set(tab_manager->profile->db, "newtab_shortcuts", data);
      g_free(data);
    }
  } else if (g_strcmp0(action, "save_bg") == 0) {
    JSCValue *data_val = jsc_value_object_get_property(value, "data");
    if (data_val && jsc_value_is_string(data_val)) {
      char *data = jsc_value_to_string(data_val);
      settings_set(tab_manager->profile->db, "newtab_bg_image", data);
      g_free(data);
    }
  } else if (g_strcmp0(action, "save_color") == 0) {
    JSCValue *data_val = jsc_value_object_get_property(value, "data");
    if (data_val && jsc_value_is_string(data_val)) {
      char *data = jsc_value_to_string(data_val);
      settings_set(tab_manager->profile->db, "newtab_font_color", data);
      g_free(data);
    }
  } else if (g_strcmp0(action, "select_bg") == 0) {
    // Open File Chooser
    GtkWidget *dialog = gtk_file_chooser_dialog_new(
        "Select Background Image", tab_manager->window,
        GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open",
        GTK_RESPONSE_ACCEPT, NULL);

    GtkFileFilter *filter = gtk_file_filter_new();
    gtk_file_filter_set_name(filter, "Images");
    gtk_file_filter_add_mime_type(filter, "image/jpeg");
    gtk_file_filter_add_mime_type(filter, "image/png");
    gtk_file_filter_add_mime_type(filter, "image/webp");
    gtk_file_filter_add_mime_type(filter, "image/gif");
    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);

    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
      char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
      // Save to DB
      settings_set(tab_manager->profile->db, "newtab_bg_image", filename);
      // Refresh page to see changes
      webkit_web_view_reload(WEBKIT_WEB_VIEW(tab->webview));
      g_free(filename);
    }
    gtk_widget_destroy(dialog);
  }

  g_free(action);
}

static Tab *create_tab(TabManager *manager, const char *url) {
  Tab *tab = g_new0(Tab, 1);

  // Create WebKit settings with developer extras enabled
  WebKitSettings *settings = webkit_settings_new();
  webkit_settings_set_enable_developer_extras(settings, TRUE);
  webkit_settings_set_enable_javascript(settings, TRUE);

  // Enable File Access for local background images
  webkit_settings_set_allow_file_access_from_file_urls(settings, TRUE);
  webkit_settings_set_allow_universal_access_from_file_urls(settings, TRUE);

  // Load hardware acceleration policy from settings
  WebKitHardwareAccelerationPolicy hw_policy =
      WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND; // Default

  if (manager->profile && manager->profile->db) {
    char *hw_setting =
        settings_get(manager->profile->db, "hardware_acceleration");
    if (hw_setting) {
      if (strcmp(hw_setting, "Always") == 0) {
        hw_policy = WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS;
      } else if (strcmp(hw_setting, "Never") == 0) {
        hw_policy = WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER;
      } else {
        hw_policy = WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND;
      }
      free(hw_setting);
    }
  }

  // Apply hardware acceleration policy
  webkit_settings_set_hardware_acceleration_policy(settings, hw_policy);

  // Enable smooth scrolling for better user experience
  webkit_settings_set_enable_smooth_scrolling(settings, TRUE);

  // Create Webview with settings
  if (manager->profile->is_private) {
    tab->webview =
        GTK_WIDGET(webkit_web_view_new_with_context(manager->profile->context));
  } else {
    // Use default context or profile's context
    if (manager->profile->context) {
      tab->webview = GTK_WIDGET(
          webkit_web_view_new_with_context(manager->profile->context));
    } else {
      tab->webview = GTK_WIDGET(webkit_web_view_new());
    }
  }

  // Apply settings to the webview
  webkit_web_view_set_settings(WEBKIT_WEB_VIEW(tab->webview), settings);
  g_object_unref(settings);

  // Setup JavaScript message handler for flags page
  WebKitUserContentManager *content_manager =
      webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(tab->webview));
  g_signal_connect(content_manager, "script-message-received::flagChanged",
                   G_CALLBACK(on_flag_changed_message), NULL);
  webkit_user_content_manager_register_script_message_handler(content_manager,
                                                              "flagChanged");

  // Setup JavaScript message handler for newtab page
  g_signal_connect(content_manager, "script-message-received::newtabUpdate",
                   G_CALLBACK(on_newtab_update_message), tab);
  webkit_user_content_manager_register_script_message_handler(content_manager,
                                                              "newtabUpdate");

  gtk_widget_show(tab->webview);

  // Create Tab Widget (EventBox with Box inside)
  tab->tab_widget = gtk_event_box_new();
  gtk_widget_set_name(tab->tab_widget, "tab-button");
  // Start as inactive tab
  gtk_style_context_add_class(gtk_widget_get_style_context(tab->tab_widget),
                              "inactive-tab");

  GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
  gtk_widget_set_margin_start(box, 8);
  gtk_widget_set_margin_end(box, 8);
  gtk_widget_set_margin_top(box, 6);
  gtk_widget_set_margin_bottom(box, 6);
  gtk_container_add(GTK_CONTAINER(tab->tab_widget), box);

  tab->label = gtk_label_new("New Tab");
  gtk_label_set_ellipsize(GTK_LABEL(tab->label), PANGO_ELLIPSIZE_END);
  gtk_label_set_max_width_chars(GTK_LABEL(tab->label), 20);
  gtk_box_pack_start(GTK_BOX(box), tab->label, TRUE, TRUE, 0);

  tab->close_btn = gtk_button_new_from_icon_name("window-close-symbolic",
                                                 GTK_ICON_SIZE_BUTTON);
  gtk_style_context_add_class(gtk_widget_get_style_context(tab->close_btn),
                              "flat");
  gtk_box_pack_end(GTK_BOX(box), tab->close_btn, FALSE, FALSE, 0);

  // Signals
  g_signal_connect(tab->tab_widget, "button-press-event",
                   G_CALLBACK(on_tab_clicked), tab);
  g_signal_connect(tab->close_btn, "clicked", G_CALLBACK(on_tab_close_clicked),
                   tab);
  g_signal_connect(tab->webview, "notify::title", G_CALLBACK(on_title_changed),
                   tab);
  g_signal_connect(tab->webview, "context-menu", G_CALLBACK(on_context_menu),
                   manager);
  g_signal_connect(tab->webview, "decide-policy", G_CALLBACK(on_decide_policy),
                   manager);

  // Right click menu handled in on_tab_clicked

  // Store manager in tab for callbacks
  g_object_set_data(G_OBJECT(tab->tab_widget), "manager", manager);
  g_object_set_data(G_OBJECT(tab->close_btn), "manager", manager);
  g_object_set_data(G_OBJECT(tab->tab_widget), "tab_ptr", tab);

  // Setup Drag and Drop
  setup_dnd(tab); // Commented out until fully implemented to avoid build errors
                  // if static function is missing

  // Apply adblock filters to this WebView
  AdblockManager *adblock_mgr = get_global_adblock_manager();
  if (adblock_mgr) {
    GError *error = NULL;
    if (!adblock_manager_apply_to_web_view(
            adblock_mgr, WEBKIT_WEB_VIEW(tab->webview), &error)) {
      g_warning("Failed to apply adblock filters to WebView: %s",
                error ? error->message : "Unknown error");
      if (error) {
        g_error_free(error);
      }
    }
  }

  // Apply YouTube adblock to this WebView
  YTAdblockManager *yt_adblock_mgr = get_global_yt_adblock_manager();
  if (yt_adblock_mgr && yt_adblock_manager_is_enabled(yt_adblock_mgr)) {
    if (!yt_adblock_manager_apply_to_webview(yt_adblock_mgr,
                                             WEBKIT_WEB_VIEW(tab->webview))) {
      g_warning("Failed to apply YouTube adblock to WebView");
    }
  }

  return tab;
}

TabManager *tab_manager_new(GtkWindow *window, Profile *profile) {
  TabManager *manager = g_new0(TabManager, 1);
  manager->window = window;
  manager->profile = profile;
  manager->tabs = NULL;

  // Header Widget (Scrolled Window containing tabs + new tab button)
  GtkWidget *scrolled = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
  gtk_widget_set_vexpand(scrolled, TRUE);
  gtk_widget_set_hexpand(scrolled, TRUE);

  manager->tabs_container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
  gtk_container_add(GTK_CONTAINER(scrolled), manager->tabs_container);

  // New tab button will be added dynamically to tabs_container
  GtkWidget *new_tab_btn =
      gtk_button_new_from_icon_name("list-add-symbolic", GTK_ICON_SIZE_BUTTON);
  gtk_style_context_add_class(gtk_widget_get_style_context(new_tab_btn),
                              "flat");
  gtk_widget_set_name(new_tab_btn, "new-tab-button");
  gtk_box_pack_end(GTK_BOX(manager->tabs_container), new_tab_btn, FALSE, FALSE,
                   0);
  g_signal_connect(new_tab_btn, "clicked", G_CALLBACK(on_new_tab_clicked),
                   manager);

  // Use the scrolled window directly as the header widget
  manager->header_box = scrolled;

  // Content Widget
  manager->content_stack = gtk_stack_new();
  gtk_stack_set_transition_type(GTK_STACK(manager->content_stack),
                                GTK_STACK_TRANSITION_TYPE_CROSSFADE);

  return manager;
}

void tab_manager_set_url_entry(TabManager *manager, GtkEntry *url_entry) {
  manager->url_entry = url_entry;
}

GtkWidget *tab_manager_get_header_widget(TabManager *manager) {
  return manager->header_box;
}

GtkWidget *tab_manager_get_content_widget(TabManager *manager) {
  return manager->content_stack;
}

void tab_manager_switch_to(TabManager *manager, Tab *tab) {
  if (!tab)
    return;

  // Remove active class from previous tab
  if (manager->current_tab && manager->current_tab != tab) {
    GtkStyleContext *old_context =
        gtk_widget_get_style_context(manager->current_tab->tab_widget);
    gtk_style_context_remove_class(old_context, "active-tab");
    gtk_style_context_add_class(old_context, "inactive-tab");
  }

  manager->current_tab = tab;
  gtk_stack_set_visible_child(GTK_STACK(manager->content_stack), tab->webview);

  // Apply active class to new tab
  GtkStyleContext *context = gtk_widget_get_style_context(tab->tab_widget);
  gtk_style_context_remove_class(context, "inactive-tab");
  gtk_style_context_add_class(context, "active-tab");

  // Update URL bar
  if (manager->url_entry) {
    const char *uri = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(tab->webview));
    if (uri) {
      gtk_entry_set_text(manager->url_entry, uri);
    } else {
      gtk_entry_set_text(manager->url_entry, "");
    }
  }
}

void tab_manager_new_tab(TabManager *manager, const char *url) {
  Tab *tab = create_tab(manager, url);
  manager->tabs = g_list_append(manager->tabs, tab);

  gtk_box_pack_start(GTK_BOX(manager->tabs_container), tab->tab_widget, FALSE,
                     FALSE, 0);
  gtk_stack_add_named(GTK_STACK(manager->content_stack), tab->webview,
                      g_strdup_printf("%p", tab));

  gtk_widget_show_all(tab->tab_widget);
  gtk_widget_show(tab->webview);

  // Initialize navigation signals for this webview to keep URL bar in sync
  if (manager->url_entry) {
    navigation_init(WEBKIT_WEB_VIEW(tab->webview), manager->url_entry,
                    manager->profile);
  }

  // Load URL
  if (url) {
    webkit_web_view_load_uri(WEBKIT_WEB_VIEW(tab->webview), url);
  } else {
    // Load home page
    // We need to access profile settings, but navigation_load_home does that.
    // We need to include navigation.h
    navigation_load_home(WEBKIT_WEB_VIEW(tab->webview), manager->profile);
  }

  tab_manager_switch_to(manager, tab);
}

static void on_tab_duplicate(GtkWidget *item, Tab *tab) {
  TabManager *manager = g_object_get_data(G_OBJECT(tab->tab_widget), "manager");
  tab_manager_duplicate_tab(manager, tab);
}

static void on_tab_close_menu(GtkWidget *item, Tab *tab) {
  TabManager *manager = g_object_get_data(G_OBJECT(tab->tab_widget), "manager");
  tab_manager_close_tab(manager, tab);
}

void tab_manager_close_tab(TabManager *manager, Tab *tab) {
  if (!tab)
    return;

  // Switch to another tab BEFORE removing this one
  if (manager->current_tab == tab) {
    if (g_list_length(manager->tabs) > 1) {
      // Find the index of current tab
      gint index = g_list_index(manager->tabs, tab);
      Tab *next = NULL;

      // Try to switch to the tab to the right, otherwise to the left
      GList *next_item = g_list_nth(manager->tabs, index + 1);
      if (next_item) {
        next = (Tab *)next_item->data;
      } else if (index > 0) {
        next_item = g_list_nth(manager->tabs, index - 1);
        if (next_item) {
          next = (Tab *)next_item->data;
        }
      }

      if (next) {
        tab_manager_switch_to(manager, next);
      }
    }
  }

  // Remove from list
  manager->tabs = g_list_remove(manager->tabs, tab);

  // Remove widgets - this will unref them
  gtk_container_remove(GTK_CONTAINER(manager->tabs_container), tab->tab_widget);
  gtk_container_remove(GTK_CONTAINER(manager->content_stack), tab->webview);

  // If no more tabs, close window
  if (!manager->tabs) {
    gtk_window_close(manager->window);
  }

  // Free the tab struct itself
  char *uri = g_strdup(webkit_web_view_get_uri(WEBKIT_WEB_VIEW(tab->webview)));
  if (uri) {
    manager->closed_tabs = g_list_prepend(manager->closed_tabs, uri);
    // Limit history to 10?
    if (g_list_length(manager->closed_tabs) > 10) {
      GList *last = g_list_last(manager->closed_tabs);
      g_free(last->data);
      manager->closed_tabs = g_list_delete_link(manager->closed_tabs, last);
    }
  }
  g_free(tab);
}

void tab_manager_reopen_last_tab(TabManager *manager) {
  if (!manager || !manager->closed_tabs)
    return;

  char *url = (char *)manager->closed_tabs->data;
  if (url) {
    tab_manager_new_tab(manager, url);
    g_free(url);
  }
  manager->closed_tabs =
      g_list_delete_link(manager->closed_tabs, manager->closed_tabs);
}

void tab_manager_next_tab(TabManager *manager) {
  if (!manager->current_tab || !manager->tabs)
    return;

  GList *current = g_list_find(manager->tabs, manager->current_tab);
  if (current && current->next) {
    tab_manager_switch_to(manager, (Tab *)current->next->data);
  } else if (manager->tabs) {
    // Cycle to first
    tab_manager_switch_to(manager, (Tab *)manager->tabs->data);
  }
}

void tab_manager_prev_tab(TabManager *manager) {
  if (!manager->current_tab || !manager->tabs)
    return;

  GList *current = g_list_find(manager->tabs, manager->current_tab);
  if (current && current->prev) {
    tab_manager_switch_to(manager, (Tab *)current->prev->data);
  } else if (manager->tabs) {
    // Cycle to last
    GList *last = g_list_last(manager->tabs);
    if (last)
      tab_manager_switch_to(manager, (Tab *)last->data);
  }
}

void tab_manager_reload_current(TabManager *manager) {
  if (manager->current_tab) {
    webkit_web_view_reload(WEBKIT_WEB_VIEW(manager->current_tab->webview));
  }
}

void tab_manager_duplicate_tab(TabManager *manager, Tab *tab) {
  if (!tab)
    return;
  const char *uri = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(tab->webview));
  tab_manager_new_tab(manager, uri);
}

void tab_manager_close_current(TabManager *manager) {
  tab_manager_close_tab(manager, manager->current_tab);
}

WebKitWebView *tab_manager_get_current_webview(TabManager *manager) {
  if (manager->current_tab) {
    return WEBKIT_WEB_VIEW(manager->current_tab->webview);
  }
  return NULL;
}

static gboolean on_tab_clicked(GtkWidget *widget, GdkEventButton *event,
                               Tab *tab) {
  TabManager *manager = g_object_get_data(G_OBJECT(widget), "manager");

  if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
    // Left click - switch to tab
    tab_manager_switch_to(manager, tab);
    return TRUE;
  } else if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
    // Right click - show context menu
    GtkWidget *menu = gtk_menu_new();

    GtkWidget *item_dup = gtk_menu_item_new_with_label("Duplicate Tab");
    g_signal_connect(item_dup, "activate", G_CALLBACK(on_tab_duplicate), tab);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), item_dup);

    GtkWidget *item_close = gtk_menu_item_new_with_label("Close Tab");
    g_signal_connect(item_close, "activate", G_CALLBACK(on_tab_close_menu),
                     tab);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), item_close);

    gtk_widget_show_all(menu);
    gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
    return TRUE;
  }

  return FALSE;
}

static void on_tab_close_clicked(GtkButton *button, Tab *tab) {
  TabManager *manager = g_object_get_data(G_OBJECT(button), "manager");
  tab_manager_close_tab(manager, tab);
}

// Drag and Drop
static void on_drag_data_get(GtkWidget *widget, GdkDragContext *context,
                             GtkSelectionData *data, guint info, guint time,
                             Tab *tab) {
  // We pass the pointer to the tab as data
  gtk_selection_data_set(data, gdk_atom_intern("TAB_POINTER", FALSE), 8,
                         (const guchar *)&tab, sizeof(Tab *));
}

static void on_drag_data_received(GtkWidget *widget, GdkDragContext *context,
                                  gint x, gint y, GtkSelectionData *data,
                                  guint info, guint time, TabManager *manager) {
  Tab **tab_ptr = (Tab **)gtk_selection_data_get_data(data);
  Tab *tab = *tab_ptr;

  // Move tab to new position
  // This is complex because we need to reorder the list and the box.
  // For MVP, let's just append to end if dropped on the container?
  // Or if dropped on another tab, insert before it.

  // Let's assume we dropped on the container for now.
  // Reordering children in GtkBox is done via gtk_box_reorder_child.

  // We need to find which tab we dropped on.
  // But this signal is on the container?
  // If we attach dnd to each tab button, we can swap.
}

static void setup_dnd(Tab *tab) {
  GtkTargetEntry targets[] = {{"TAB_POINTER", GTK_TARGET_SAME_APP, 0}};
  gtk_drag_source_set(tab->tab_widget, GDK_BUTTON1_MASK, targets, 1,
                      GDK_ACTION_MOVE);
  g_signal_connect(tab->tab_widget, "drag-data-get",
                   G_CALLBACK(on_drag_data_get), tab);

  // We also need to set dest on the container or other tabs.
}

static void on_new_tab_clicked(GtkButton *button, TabManager *manager) {
  tab_manager_new_tab(manager, NULL);
}
