use tauri::{AppHandle, Emitter, Manager, WebviewUrl, WebviewWindowBuilder};

const PICKER_BRIDGE: &str = include_str!("picker_bridge.js");
const PREVIEW_LABEL: &str = "preview";

/// Open or reuse a preview window for a localhost URL.
/// `instance_id` is generated by the frontend to correlate events.
#[tauri::command]
pub async fn open_preview_window(
    app: AppHandle,
    url: String,
    instance_id: String,
) -> Result<(), String> {
    let parsed_url = validate_localhost(&url)?;

    log::debug!(
        "[preview] open_preview_window: url={}, instance_id={}",
        url,
        instance_id
    );

    // Destroy existing preview window before creating a new one
    if let Some(win) = app.get_webview_window(PREVIEW_LABEL) {
        win.destroy().map_err(|e| e.to_string())?;
    }

    let app_for_nav = app.clone();
    let app_for_close = app.clone();
    let iid_nav = instance_id.clone();
    let iid_close = instance_id.clone();

    let win = WebviewWindowBuilder::new(&app, PREVIEW_LABEL, WebviewUrl::External(parsed_url))
        .title("Preview")
        .inner_size(1024.0, 768.0)
        // Inject picker bridge as initialization script — runs before page JS on every navigation,
        // much faster than waiting for on_page_load(Finished) + eval().
        .initialization_script(PICKER_BRIDGE)
        .on_navigation(move |url| {
            if url.scheme() == "ocv-bridge" {
                if let Some(fragment) = url.fragment() {
                    match urlencoding::decode(fragment) {
                        Ok(json) => match serde_json::from_str::<serde_json::Value>(&json) {
                            Ok(data) => {
                                log::debug!(
                                    "[preview] element selected, payload len={}",
                                    json.len()
                                );
                                let _ = app_for_nav.emit(
                                    "preview-element-selected",
                                    serde_json::json!({
                                        "instanceId": iid_nav,
                                        "data": data,
                                    }),
                                );
                            }
                            Err(e) => {
                                log::warn!("[preview] element payload JSON invalid: {}", e);
                            }
                        },
                        Err(e) => log::warn!("[preview] URL decode failed: {}", e),
                    }
                }
                return false; // block navigation
            }
            // Allow all other navigations — the page may need external auth
            // (e.g. Clerk, OAuth). Initial URL is validated by validate_localhost().
            true
        })
        .build()
        .map_err(|e| format!("preview_open_failed: {}", e))?;

    // Emit event when preview window is destroyed (user closes it manually)
    win.on_window_event(move |event| {
        if let tauri::WindowEvent::Destroyed = event {
            log::debug!("[preview] window destroyed, instance_id={}", iid_close);
            let _ = app_for_close.emit(
                "preview-window-closed",
                serde_json::json!({ "instanceId": iid_close }),
            );
        }
    });

    Ok(())
}

#[tauri::command]
pub async fn close_preview_window(app: AppHandle) -> Result<(), String> {
    log::debug!("[preview] close_preview_window");
    if let Some(win) = app.get_webview_window(PREVIEW_LABEL) {
        win.destroy().map_err(|e| e.to_string())?;
    }
    Ok(())
}

/// Validate URL is localhost http/https, return parsed URL.
fn validate_localhost(url: &str) -> Result<url::Url, String> {
    let parsed = url::Url::parse(url).map_err(|e| format!("preview_invalid_url: {e}"))?;
    let host = parsed.host_str().unwrap_or("");
    if !["localhost", "127.0.0.1", "0.0.0.0", "::1"].contains(&host) {
        return Err(format!(
            "preview_invalid_url: only localhost allowed, got {}",
            host
        ));
    }
    if !["http", "https"].contains(&parsed.scheme()) {
        return Err(format!(
            "preview_invalid_url: only http/https allowed, got {}",
            parsed.scheme()
        ));
    }
    Ok(parsed)
}
