
use crate::io::get_app_dirs;
use crate::io::storage::Storage;
use crate::messagebox::MessageBox;
use crate::natives_and_messaging::*;
use crate::window::{Application, Frame};

#[cfg(windows)]
/// Run nxui::window::Application
#[no_mangle] pub extern "C" fn create_new_app(application: Box<dyn Application>) {
    // Get window title
    let app_name = application.app_name();
    // Get attributes
    let attributes = application.attributes();
    let storage = Storage::new(get_app_dirs(app_name));
    let advanced_option = application.advanced_options();
    // startup process
    if application.is_child_window() == false {
        storage.create_app_dir();
    }
    application.startup(storage);

    // Create a window
    use windows_sys::{
        Win32::Foundation::*, Win32::System::LibraryLoader::GetModuleHandleA,
        Win32::UI::WindowsAndMessaging::*,
    };
    extern "system" fn wndproc(
        window: HWND,
        message: u32,
        wparam: WPARAM,
        lparam: LPARAM,
    ) -> LRESULT {
        unsafe {
            match message as u32 {
                WM_DESTROY => {
                    println!("WM_DESTROY");
                    PostQuitMessage(0);
                    0
                }

                _ => DefWindowProcA(window, message, wparam, lparam),
            }
        }
    }

    unsafe {
        let instance = GetModuleHandleA(std::ptr::null_mut());
        debug_assert!(instance != 0);
        use windows_sys::Win32::Graphics::Gdi::HBRUSH;
        let wc = WNDCLASSA {
            hCursor: LoadCursorW(0, IDC_ARROW),
            hInstance: instance,
            lpszClassName: "window".as_ptr(),
            style: CS_HREDRAW | CS_VREDRAW,
            lpfnWndProc: Some(wndproc),
            cbClsExtra: 0,
            cbWndExtra: 0,
            hIcon: 0,
            hbrBackground: advanced_option.get_background_color() as HBRUSH,
            lpszMenuName: std::ptr::null_mut(),
        };

        let atom = RegisterClassA(&wc);
        debug_assert!(atom != 0);
        let win = CreateWindowExA(
            advanced_option.get_style(),
            b"window".as_ptr(),
            format!("{}\0", attributes.title).as_ptr(),
            attributes.style | WS_VISIBLE,
            attributes.x,
            attributes.y,
            attributes.width,
            attributes.height,
            0,
            0,
            instance,
            std::ptr::null_mut(),
        );
        if win == 0 {
            MessageBox::new("NXUI Error", "NXUI Error - Code 0001\rWindow could not be initialized\r \rDetailed information:\rPanicked at nxui::nxui::create_new_app()\rTo resolve this error, contact the application developer or\rPlease report at https://github.com/LatteSyobon/nxui/issues", DS_ERROR, BS_OK).show(Frame::default());
            panic!("Window could not be initialized");
        }

        info!("A window has been created. handle: {}", win);

        let frame = Frame::new(win);
        info!("Frame has been created.");
        info!("UI Phase");
        application.ui(&frame);

        let mut message = std::mem::zeroed();

        while GetMessageA(&mut message, 0, 0, 0) != 0 {
            TranslateMessage(&message);
            DispatchMessageA(&message);
        }
        info!("Exit Phase");
        application.exit();
    }
}

#[cfg(unix)]
/// Run nxui::window::Application
#[no_mangle] pub extern "C" fn create_new_app(application: Box<dyn Application>) {
    // Get window title
    let app_name = application.app_name();
    // Get attributes
    let attributes = application.attributes();
    // Get advanced_options
    let advanced_options = application.advanced_options();
    let storage = Storage::new(get_app_dirs(app_name));
    // startup process
    if application.is_child_window() == false {
        storage.create_app_dir();
    }
    application.startup(storage);

    // Create a window
    use gtk::prelude::*;

    let app = gtk::Application::new(Option::from(attributes.app_id.as_str()), Default::default());
    app.connect_activate(move |app: &gtk::Application| {
        let window = gtk::ApplicationWindow::new(app);
        info!("A window has been created. handle: {}", window);

        window.set_title(attributes.title.as_str());
        window.set_default_size(attributes.width, attributes.height);
        window.set_window_position(gtk::WindowPosition::Center);
        window.set_type_hint(advanced_options.get_style());

        let frame = Frame::new(window.clone(), window.application());
        info!("Frame has been created.");
        info!("UI Phase");
        application.ui(&frame);

        window.show_all();
    });

    app.run();
    //info!("UI Exit");
    //application.exit();
}
