/**
 * GTK-native window resize — mirrors Tauri/tao's approach.
 *
 * Connects button-press-event and motion-notify-event directly on the
 * GtkWindow via FFI. Hit-test and begin_resize_drag happen SYNCHRONOUSLY
 * in the native GTK event loop, BEFORE WebKitGTK sees the events.
 */

import { dlopen, FFIType, JSCallback, ptr } from "bun:ffi";

const BORDER = 8;
const EDGE_NW = 0, EDGE_N = 1, EDGE_NE = 2;
const EDGE_W = 3, EDGE_E = 4;
const EDGE_SW = 5, EDGE_S = 6, EDGE_SE = 7;
const CURSORS = ["nw-resize","n-resize","ne-resize","w-resize","","e-resize","sw-resize","s-resize","se-resize"];

let gtk: ReturnType<typeof dlopen> | null = null;
function getLib() {
  if (gtk) return gtk;
  gtk = dlopen("libgtk-3.so.0", {
    gtk_widget_add_events: { args: [FFIType.ptr, FFIType.i32], returns: FFIType.void },
    gtk_window_begin_resize_drag: { args: [FFIType.ptr, FFIType.i32, FFIType.i32, FFIType.i32, FFIType.i32, FFIType.u32], returns: FFIType.void },
    gtk_widget_get_window: { args: [FFIType.ptr], returns: FFIType.ptr },
    g_signal_connect_data: { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.i32], returns: FFIType.u64 },
    gdk_window_get_position: { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.void },
    gdk_window_get_width: { args: [FFIType.ptr], returns: FFIType.i32 },
    gdk_window_get_height: { args: [FFIType.ptr], returns: FFIType.i32 },
    gdk_cursor_new_from_name: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.ptr },
    gdk_window_set_cursor: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.void },
    gdk_display_get_default: { args: [], returns: FFIType.ptr },
    gdk_event_get_button: { args: [FFIType.ptr, FFIType.ptr], returns: FFIType.bool },
    gdk_event_get_root_coords: { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.bool },
    gdk_event_get_time: { args: [FFIType.ptr], returns: FFIType.u32 },
  });
  return gtk;
}

function hitTest(l: number, t: number, r: number, b: number, cx: number, cy: number, border: number): number {
  const oL = cx < l + border, oR = cx >= r - border, oT = cy < t + border, oB = cy >= b - border;
  if (oT && oL) return EDGE_NW; if (oT && oR) return EDGE_NE;
  if (oB && oL) return EDGE_SW; if (oB && oR) return EDGE_SE;
  if (oT) return EDGE_N; if (oB) return EDGE_S;
  if (oL) return EDGE_W; if (oR) return EDGE_E;
  return -1;
}

// Module-level state — set by installNativeResize, read by callbacks
let storedWindowPtr: any = null;
let motionCb: JSCallback | null = null;
let buttonCb: JSCallback | null = null;

// Shared buffers — use Buffer.alloc for reliable FFI pointer passing
const xBuf = Buffer.alloc(8); // gdouble (8 bytes)
const yBuf = Buffer.alloc(8);
const btnBuf = Buffer.alloc(4); // guint (4 bytes)
const posXBuf = Buffer.alloc(4); // gint (4 bytes)
const posYBuf = Buffer.alloc(4);

function getWindowBounds() {
  if (!gtk || !storedWindowPtr) return null;
  const gdkWin = gtk.symbols.gtk_widget_get_window(storedWindowPtr);
  if (!gdkWin) return null;
  gtk.symbols.gdk_window_get_position(gdkWin, ptr(posXBuf) as any, ptr(posYBuf) as any);
  const w = gtk.symbols.gdk_window_get_width(gdkWin);
  const h = gtk.symbols.gdk_window_get_height(gdkWin);
  const left = posXBuf.readInt32LE(0);
  const top = posYBuf.readInt32LE(0);
  return { left, top, right: left + w, bottom: top + h };
}

export function installNativeResize(windowPtr: number | bigint) {
  const lib = getLib();
  if (!lib) { console.error("[gtk-resize] Failed to load libgtk-3.so.0"); return; }
  storedWindowPtr = windowPtr;

  // Add event masks
  lib.symbols.gtk_widget_add_events(windowPtr as any, (1<<2) | (1<<8) | (1<<5));

  // Motion handler skipped — cursor feedback provided by CSS resize handles instead.
  // The FFI motion callback causes crashes in Bun's JSCallback bridge.

  // Button press — initiate resize if in border zone
  buttonCb = new JSCallback(
    (_w: any, event: any, _u: any) => {
      try {
        gtk!.symbols.gdk_event_get_button(event, ptr(btnBuf) as any);
        if (btnBuf.readUInt32LE(0) !== 1) return 0; // LMB only

        gtk!.symbols.gdk_event_get_root_coords(event, ptr(xBuf) as any, ptr(yBuf) as any);
        const cx = xBuf.readDoubleLE(0);
        const cy = yBuf.readDoubleLE(0);
        const bounds = getWindowBounds();
        if (!bounds) return 0;

        const edge = hitTest(bounds.left, bounds.top, bounds.right, bounds.bottom, cx, cy, BORDER);
        if (edge < 0) return 0; // Inside content — let WebKit handle

        const timestamp = gtk!.symbols.gdk_event_get_time(event);
        console.log(`[gtk-resize] begin_resize_drag edge=${edge} t=${timestamp}`);

        gtk!.symbols.gtk_window_begin_resize_drag(
          storedWindowPtr, edge, 1,
          Math.round(cx), Math.round(cy),
          timestamp,
        );
        return 1; // TRUE — STOP propagation
      } catch (e) { console.error("[gtk-resize] button error:", e); return 0; }
    },
    { args: [FFIType.ptr, FFIType.ptr, FFIType.ptr], returns: FFIType.i32 },
  );

  const sigBP = Buffer.from("button-press-event\0");
  lib.symbols.g_signal_connect_data(windowPtr as any, ptr(sigBP) as any, buttonCb.ptr as any, null, null, 0);
  // Motion signal NOT connected — cursor feedback via CSS handles instead

  console.log("[gtk-resize] Native resize handlers installed (border=" + BORDER + "px)");
}
