use axum::{routing::get, Router};
use eframe::egui;
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
use serde::{Deserialize, Serialize};
use std::{
    net::SocketAddr,
    sync::{Arc, Mutex},
    thread,
};
use tokio::task::JoinHandle;
use tokio::{net::TcpListener, sync::mpsc};
use tray_item::TrayItem;

#[derive(Debug, Clone)]
struct AppState {
    settings: Arc<Mutex<ServerSettings>>,
    should_run: Arc<Mutex<bool>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct ServerSettings {
    port: String,
}

async fn home() -> &'static str {
    "Hello, World!"
}

#[tokio::main]
async fn main() {
    let (tx, rx) = mpsc::channel(32);
    let settings = Arc::new(Mutex::new(ServerSettings {
        port: "3311".to_string(),
    }));
    let should_run = Arc::new(Mutex::new(true));
    let app_state = AppState {
        settings: settings.clone(),
        should_run: should_run.clone(),
    };

    // Run the server in a separate thread
    let server_thread = thread::spawn(move || {
        let rt = tokio::runtime::Runtime::new().unwrap();
        rt.block_on(async {
            run_server(app_state, rx).await;
        });
    });

    // Run the UI on the main thread
    run_ui(settings, should_run, tx);

    // Wait for the server thread to finish
    server_thread.join().unwrap();
}

async fn run_server(app_state: AppState, mut rx: mpsc::Receiver<ServerMessage>) {
    let mut server_handle = start_server(&app_state);

    loop {
        tokio::select! {
            _ = &mut server_handle => {
                // Server has stopped
                eprintln!("Server stopped.");
                break;
            },
            Some(message) = rx.recv() => {
                match message {
                    // This is the message type that actually restarts the server.
                    ServerMessage::UpdateSettings(new_settings) => {
                        println!("Received new settings: {:?}", new_settings);
                        let mut settings_guard = app_state.settings.lock().unwrap();
                        *settings_guard = new_settings;

                        // Restart the server with new settings
                        println!("Aborting current server...");
                        server_handle.abort(); // Cancel the previous server task
                        println!("Starting new server...");
                        drop(settings_guard); // Ensure the lock is released before starting the new server
                        server_handle = start_server(&app_state);
                        println!("Server started.");
                    },
                    ServerMessage::Shutdown => {
                        // Handle server shutdown
                        println!("Shutting down server...");
                        let mut should_run_guard = app_state.should_run.lock().unwrap();
                        *should_run_guard = false;
                        server_handle.abort();
                        println!("Server shutdown.");
                        break;
                    },
                    // Handle other message types here
                    ServerMessage::Interact => {
                        // Example interaction: print current settings
                        let settings_guard = app_state.settings.lock().unwrap();
                        println!("Current settings: {:?}", *settings_guard);
                    },
                }
            }
        }
    }
}

fn start_server(app_state: &AppState) -> JoinHandle<()> {
    // Compute the address before entering the async block
    let addr = {
        let settings = app_state.settings.lock().unwrap();
        let port: u16 = settings.port.parse().unwrap_or(3311);
        SocketAddr::from(([0, 0, 0, 0], port))
    };

    let server_app_state = app_state.clone();

    println!("listening on {}", addr);

    tokio::spawn(async move {
        let app = Router::new()
            .route("/", get(home))
            .with_state(server_app_state.clone());
        let listener = TcpListener::bind(&addr).await.unwrap();
        let server = axum::serve(listener, app.into_make_service());

        server.await;
    })
}

async fn monitor_shutdown(should_run: Arc<Mutex<bool>>) {
    while *should_run.lock().unwrap() {
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    }
}

fn run_ui(
    settings: Arc<Mutex<ServerSettings>>,
    should_run: Arc<Mutex<bool>>,
    tx: mpsc::Sender<ServerMessage>,
) {
    // Create an atomic bool to track window visibility
    static VISIBLE: once_cell::sync::Lazy<Mutex<bool>> =
        once_cell::sync::Lazy::new(|| Mutex::new(true));

    let native_options = eframe::NativeOptions::default();
    eframe::run_native(
        "App",
        native_options,
        Box::new(|cc| {
            // Set up the tray icon event handler
            let window_handle = cc.window_handle().unwrap();
            let window_handle = window_handle.as_raw();
            let mut tray =
                TrayItem::new("App Name", tray_item::IconSource::Resource("icon-red")).unwrap();
            if let RawWindowHandle::Win32(handle) = window_handle {
                // Windows Only.
                use windows::Win32::Foundation::HWND;
                use windows::Win32::UI::WindowsAndMessaging::{
                    ShowWindow,
                    SW_HIDE,
                    SW_RESTORE, // SW_SHOWDEFAULT, SW_SHOWNORMAL,
                };

                tray.add_label("Server Control").unwrap();

                tray.add_menu_item("Show/Hide", {
                    move || {
                        let mut visible_lock = VISIBLE.lock().unwrap();
                        let window_handle = HWND(handle.hwnd.into());

                        if *visible_lock {
                            unsafe {
                                _ = ShowWindow(window_handle, SW_HIDE);
                            }
                            *visible_lock = false;
                        } else {
                            unsafe {
                                _ = ShowWindow(window_handle, SW_RESTORE);
                            }
                            *visible_lock = true;
                        }
                    }
                })
                .unwrap();
            } else {
                println!("Unsupported platform for tray icon.");
            }

            tray.add_menu_item("Quit", move || {
                std::process::exit(0);
            })
            .unwrap();

            let app = NativeApp {
                settings,
                should_run,
                tx,
                tray,
            };

            Box::new(app)
        }),
    )
    .expect("Error running UI.");
}

struct NativeApp {
    settings: Arc<Mutex<ServerSettings>>,
    #[allow(dead_code)]
    should_run: Arc<Mutex<bool>>,
    tx: mpsc::Sender<ServerMessage>,
    #[allow(dead_code)]
    tray: TrayItem,
}

impl eframe::App for NativeApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            let mut settings = self.settings.lock().unwrap();

            ui.heading("Server Settings");

            ui.horizontal(|ui| {
                ui.label("Port:");
                if ui.text_edit_singleline(&mut settings.port).changed() {}
            });

            if ui.button("Apply").clicked() {
                if self
                    .tx
                    .try_send(ServerMessage::UpdateSettings(settings.clone()))
                    .is_err()
                {
                    eprintln!("Failed to send settings update");
                }
            }

            if ui.button("Interact").clicked() {
                if self.tx.try_send(ServerMessage::Interact).is_err() {
                    eprintln!("Failed to send interaction message");
                }
            }

            if ui.button("Shutdown Server").clicked() {
                if self.tx.try_send(ServerMessage::Shutdown).is_err() {
                    eprintln!("Failed to send shutdown message");
                }
            }
        });
    }

    fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
        if self.tx.try_send(ServerMessage::Shutdown).is_err() {
            eprintln!("Failed to send shutdown message");
        }
    }
}

#[derive(Debug, Clone)]
enum ServerMessage {
    UpdateSettings(ServerSettings),
    Interact,
    Shutdown,
    // Add other message types here
}