use gtk::prelude::*; // Keep this if extension traits are needed, otherwise remove. Window uses it.
use gtk::{glib, gdk}; // Window uses gdk, glib.
use gtk::gdk::Monitor;
use std::ffi::c_void;
use std::marker::PhantomData;
use std::ptr; // Import ptr
use glib::translate::from_glib_none;
use crate::state::WindowData;

#[repr(C)]
pub struct __IncompleteArrayField<T>(PhantomData<T>);

impl<T> __IncompleteArrayField<T> {
    pub const fn new() -> Self {
        Self(PhantomData)
    }

    /// # Safety
    /// Returns a raw pointer to the field. The caller must ensure the struct was allocated
    /// with enough space for this flexible array member.
    pub unsafe fn as_ptr(&self) -> *mut T {
        self as *const _ as *mut T
    }
}

impl<T> Default for __IncompleteArrayField<T> {
    fn default() -> Self {
        Self::new()
    }
}

#[repr(C)]
pub struct Window {
    pub monitor: *mut gdk::ffi::GdkMonitor,
    pub window: *mut gtk::ffi::GtkWidget,
    pub overlay: *mut gtk::ffi::GtkOverlay,
    pub window_box: *mut gtk::ffi::GtkWidget,
    pub body_revealer: *mut gtk::ffi::GtkWidget,
    pub body_grid: *mut gtk::ffi::GtkWidget,
    pub input_label: *mut gtk::ffi::GtkWidget,
    pub input_field: *mut gtk::ffi::GtkWidget,
    pub message_revealer: *mut gtk::ffi::GtkWidget,
    pub message_scrolled_window: *mut gtk::ffi::GtkWidget,
    pub message_box: *mut gtk::ffi::GtkWidget,
    pub unlock_button: *mut gtk::ffi::GtkWidget,
    pub error_label: *mut gtk::ffi::GtkWidget,
    pub warning_label: *mut gtk::ffi::GtkWidget,
    pub info_box: *mut gtk::ffi::GtkWidget,
    pub time_box: *mut gtk::ffi::GtkWidget,
    pub clock_label: *mut gtk::ffi::GtkWidget,
    pub date_label: *mut gtk::ffi::GtkWidget,
    pub module_data: __IncompleteArrayField<*mut c_void>,
}

#[repr(C)]
pub struct GtkLock {
    pub windows: *mut glib::ffi::GArray,
}

// Safe wrapper for Window pointer operations
pub struct WindowContext(*mut Window);

impl WindowContext {
    /// # Safety
    /// `ctx` must be a valid pointer to a `Window` struct.
    pub unsafe fn new(ctx: *mut Window) -> Option<Self> {
        if ctx.is_null() {
            None
        } else {
            Some(Self(ctx))
        }
    }

    pub unsafe fn get_error_label(&self) -> gtk::Label {
        from_glib_none((*self.0).error_label as *mut gtk::ffi::GtkLabel)
    }

    pub unsafe fn get_overlay(&self) -> gtk::Overlay {
        from_glib_none((*self.0).overlay as *mut gtk::ffi::GtkOverlay)
    }

    pub unsafe fn get_monitor(&self) -> Monitor {
        from_glib_none((*self.0).monitor as *mut gdk::ffi::GdkMonitor)
    }

    /// # Safety
    /// The caller must ensure `module_data` has been initialized and points to a valid `WindowData`.
    pub unsafe fn set_data(&self, data: Box<WindowData>) {
        let raw_ptr = Box::into_raw(data);
        (*(*self.0).module_data.as_ptr()) = raw_ptr as *mut c_void;
    }

    pub unsafe fn get_data_ptr(&self) -> *mut WindowData {
        *(*self.0).module_data.as_ptr() as *mut WindowData
    }

    /// # Safety
    /// The caller takes ownership of the data and must drop it.
    pub unsafe fn take_data(&self) -> Option<Box<WindowData>> {
        let ptr_ref = (*self.0).module_data.as_ptr();
        let ptr = *ptr_ref;
        if ptr.is_null() {
            None
        } else {
            *ptr_ref = ptr::null_mut(); // Clear it
            Some(Box::from_raw(ptr as *mut WindowData))
        }
    }
}

