use crate::screenshot::take_area_screenshot;
use tauri::App;
use tauri::AppHandle;
use tauri::Emitter;
use tauri::Manager;
use tauri::Runtime;
use tauri_plugin_global_shortcut::GlobalShortcutExt;
use tauri_plugin_global_shortcut::Shortcut;
use tauri_plugin_global_shortcut::ShortcutState;
use tauri_plugin_store::JsonValue;
use tauri_plugin_store::StoreExt;

/// Constants for Tauri store configuration
const HAYSTACK_TAURI_STORE: &str = "haystack_tauri_store"; // Name of the persistent store
const HAYSTACK_GLOBAL_SHORTCUT: &str = "haystack_global_shortcut"; // Key for storing the toggle window shortcut
const HAYSTACK_SCREENSHOT_SHORTCUT: &str = "haystack_screenshot_shortcut"; // Key for storing the screenshot shortcut

/// Platform-specific default shortcuts
#[cfg(target_os = "macos")]
const DEFAULT_SHORTCUT: &str = "command+shift+k"; // macOS uses Command key
#[cfg(target_os = "macos")]
const DEFAULT_SCREENSHOT_SHORTCUT: &str = "command+shift+p"; // macOS screenshot shortcut

#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_SHORTCUT: &str = "ctrl+shift+k"; // Windows/Linux use Ctrl key
#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_SCREENSHOT_SHORTCUT: &str = "ctrl+shift+p"; // Windows/Linux screenshot shortcut

/// Initializes the global shortcut during application startup.
/// This function:
/// 1. Checks if a shortcut is already stored
/// 2. Uses the stored shortcut if it exists
/// 3. Falls back to the platform-specific default if no shortcut is stored
/// 4. Registers the shortcut with the system
pub fn enable_shortcut(app: &App) {
    // Get or create the persistent store
    let store = app
        .store(HAYSTACK_TAURI_STORE)
        .expect("Creating the store should not fail");

    // Initialize toggle window shortcut
    let toggle_shortcut = if let Some(stored_shortcut) = store.get(HAYSTACK_GLOBAL_SHORTCUT) {
        let stored_shortcut_str = match stored_shortcut {
            JsonValue::String(str) => str,
            unexpected_type => panic!(
                "Haystack shortcuts should be stored as strings, found type: {} ",
                unexpected_type
            ),
        };
        stored_shortcut_str
            .parse::<Shortcut>()
            .expect("Stored shortcut string should be valid")
    } else {
        store.set(
            HAYSTACK_GLOBAL_SHORTCUT,
            JsonValue::String(DEFAULT_SHORTCUT.to_string()),
        );
        DEFAULT_SHORTCUT
            .parse::<Shortcut>()
            .expect("Default shortcut should be valid")
    };

    // Initialize screenshot shortcut
    let screenshot_shortcut = if let Some(stored_shortcut) = store.get(HAYSTACK_SCREENSHOT_SHORTCUT)
    {
        let stored_shortcut_str = match stored_shortcut {
            JsonValue::String(str) => str,
            unexpected_type => panic!(
                "Haystack shortcuts should be stored as strings, found type: {} ",
                unexpected_type
            ),
        };
        stored_shortcut_str
            .parse::<Shortcut>()
            .expect("Stored shortcut string should be valid")
    } else {
        store.set(
            HAYSTACK_SCREENSHOT_SHORTCUT,
            JsonValue::String(DEFAULT_SCREENSHOT_SHORTCUT.to_string()),
        );
        DEFAULT_SCREENSHOT_SHORTCUT
            .parse::<Shortcut>()
            .expect("Default screenshot shortcut should be valid")
    };

    // Register both shortcuts
    register_shortcut_upon_start(app, toggle_shortcut, screenshot_shortcut);
}

/// Returns the currently configured shortcut as a string.
/// This is exposed as a Tauri command for the frontend to query.
#[tauri::command]
pub fn get_current_shortcut<R: Runtime>(app: AppHandle<R>) -> Result<String, String> {
    Ok(get_shortcut_from_store(&app))
}

/// Unregisters the current global shortcut from the system.
/// This is exposed as a Tauri command for the frontend to trigger.
#[tauri::command]
pub fn unregister_shortcut<R: Runtime>(app: AppHandle<R>) {
    let shortcut_str = get_shortcut_from_store(&app);
    let shortcut = shortcut_str
        .parse::<Shortcut>()
        .expect("Stored shortcut string should be valid");

    app.global_shortcut()
        .unregister(shortcut)
        .expect("Failed to unregister shortcut")
}

/// Changes the global shortcut to a new key combination.
/// This function:
/// 1. Validates the new shortcut
/// 2. Stores it in the persistent store
/// 3. Registers it with the system
#[tauri::command]
pub fn change_shortcut<R: Runtime>(
    app: AppHandle<R>,
    _window: tauri::Window<R>,
    key: String,
) -> Result<(), String> {
    println!("Key: {}", key);
    let shortcut = match key.parse::<Shortcut>() {
        Ok(shortcut) => shortcut,
        Err(_) => return Err(format!("Invalid shortcut {}", key)),
    };

    // Store the new shortcut
    let store = app
        .get_store(HAYSTACK_TAURI_STORE)
        .expect("Store should already be loaded or created");
    store.set(HAYSTACK_GLOBAL_SHORTCUT, JsonValue::String(key));

    // Register the new shortcut
    register_shortcut(&app, shortcut);

    Ok(())
}

/// Handles the window visibility toggle logic when the shortcut is pressed.
/// This function:
/// 1. Hides the window if it's visible
/// 2. Shows and focuses the window if it's hidden
/// 3. Emits a 'focus-search' event when showing the window
fn handle_window_visibility<R: Runtime>(app: &AppHandle<R>, window: &tauri::WebviewWindow<R>) {
    if window.is_visible().unwrap() {
        window.hide().unwrap();
    } else {
        window.show().unwrap();
        window.set_focus().unwrap();
        app.emit("focus-search", ()).unwrap();
    }
}

/// Registers a new shortcut with the system.
/// This is used when changing shortcuts during runtime.
/// The function:
/// 1. Gets the main window
/// 2. Sets up the shortcut handler
/// 3. Registers the shortcut with the system
fn register_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
    let main_window = app.get_webview_window("main").unwrap();

    app.global_shortcut()
        .on_shortcut(shortcut, move |app, scut, event| {
            if scut == &shortcut {
                if let ShortcutState::Pressed = event.state() {
                    handle_window_visibility(app, &main_window);
                }
            }
        })
        .map_err(|err| format!("Failed to register new shortcut '{}'", err))
        .unwrap();
}

/// Registers a shortcut during application startup.
/// This is similar to register_shortcut but handles the initial plugin setup.
/// The function:
/// 1. Gets the main window
/// 2. Sets up the global shortcut plugin
/// 3. Registers the shortcut with the system
fn register_shortcut_upon_start(
    app: &App,
    toggle_shortcut: Shortcut,
    screenshot_shortcut: Shortcut,
) {
    let window = app
        .get_webview_window("main")
        .expect("webview to be defined");

    app.handle()
        .plugin(
            tauri_plugin_global_shortcut::Builder::new()
                .with_handler(move |app, scut, event| {
                    if scut == &toggle_shortcut {
                        if let ShortcutState::Pressed = event.state() {
                            handle_window_visibility(app, &window);
                        }
                    } else if scut == &screenshot_shortcut {
                        if let ShortcutState::Pressed = event.state() {
                            // TODO: Implement screenshot functionality
                            println!("Screenshot shortcut pressed");
                        }
                        if let Err(e) = take_area_screenshot(app) {
                            println!("Failed to take screenshot: {}", e);
                        }
                    }
                })
                .build(),
        )
        .unwrap();
    app.global_shortcut().register(toggle_shortcut).unwrap();
    app.global_shortcut().register(screenshot_shortcut).unwrap();
}

/// Retrieves the currently stored shortcut from the persistent store.
/// This is a helper function used by other functions to access the stored shortcut.
fn get_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String {
    let store = app
        .get_store(HAYSTACK_TAURI_STORE)
        .expect("Store should already be loaded or created");

    match store
        .get(HAYSTACK_GLOBAL_SHORTCUT)
        .expect("Shortcut should already be stored")
    {
        JsonValue::String(str) => str,
        unexpected_type => panic!(
            "Haystack shortcuts should be stored as strings, found type: {} ",
            unexpected_type
        ),
    }
}

#[tauri::command]
pub fn get_current_screenshot_shortcut<R: Runtime>(app: AppHandle<R>) -> Result<String, String> {
    Ok(get_screenshot_shortcut_from_store(&app))
}

#[tauri::command]
pub fn unregister_screenshot_shortcut<R: Runtime>(app: AppHandle<R>) {
    let shortcut_str = get_screenshot_shortcut_from_store(&app);
    let shortcut = shortcut_str
        .parse::<Shortcut>()
        .expect("Stored shortcut string should be valid");

    app.global_shortcut()
        .unregister(shortcut)
        .expect("Failed to unregister screenshot shortcut")
}

#[tauri::command]
pub fn change_screenshot_shortcut<R: Runtime>(
    app: AppHandle<R>,
    _window: tauri::Window<R>,
    key: String,
) -> Result<(), String> {
    let shortcut = match key.parse::<Shortcut>() {
        Ok(shortcut) => shortcut,
        Err(_) => return Err(format!("Invalid screenshot shortcut {}", key)),
    };

    let store = app
        .get_store(HAYSTACK_TAURI_STORE)
        .expect("Store should already be loaded or created");
    store.set(HAYSTACK_SCREENSHOT_SHORTCUT, JsonValue::String(key));

    register_screenshot_shortcut(&app, shortcut);

    Ok(())
}

fn register_screenshot_shortcut<R: Runtime>(app: &AppHandle<R>, shortcut: Shortcut) {
    app.global_shortcut()
        .on_shortcut(shortcut, move |app, scut, event| {
            if scut == &shortcut {
                if let ShortcutState::Pressed = event.state() {
                    if let Err(e) = take_area_screenshot(app) {
                        println!("Failed to take screenshot: {}", e);
                    }
                }
            }
        })
        .map_err(|err| format!("Failed to register new screenshot shortcut '{}'", err))
        .unwrap();
}

fn get_screenshot_shortcut_from_store<R: Runtime>(app: &AppHandle<R>) -> String {
    let store = app
        .get_store(HAYSTACK_TAURI_STORE)
        .expect("Store should already be loaded or created");

    match store
        .get(HAYSTACK_SCREENSHOT_SHORTCUT)
        .expect("Screenshot shortcut should already be stored")
    {
        JsonValue::String(str) => str,
        unexpected_type => panic!(
            "Haystack shortcuts should be stored as strings, found type: {} ",
            unexpected_type
        ),
    }
}
