use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use std::process::{Command, Output};
use std::{fs, path::PathBuf};
use tauri::{AppHandle, Emitter, Runtime};

#[cfg(target_os = "macos")]
fn screenshot(path: &PathBuf) -> Result<Output, String> {
    Command::new("screencapture")
        .arg("-i") // interactive selection
        .arg("-x") // don't play sound
        .arg("-o") // don't show cursor
        .arg("-r") // don't add shadow
        .arg(path.to_str().unwrap())
        .output()
        .map_err(|e| format!("Failed to execute screencapture: {}", e))
}

#[cfg(target_os = "linux")]
fn screenshot(path: &PathBuf) -> Result<Output, String> {
    let slurp_output = Command::new("slurp")
        .output()
        .map_err(|e| format!("Failed to execute screencapture: {}", e))?;

    if !slurp_output.status.success() {
        let stderr = String::from_utf8_lossy(&slurp_output.stderr);
        if slurp_output.status.code() == Some(1) && stderr.is_empty() {
            log::warn!("slurp cancelled by user.");
            return Err("Screenshot cancelled by user.".to_string());
        }
        return Err(format!(
            "slurp failed. Status: {:?}, Stderr: {}",
            slurp_output.status, stderr
        ));
    }

    let geometry = String::from_utf8(slurp_output.stdout)
        .map_err(|e| format!("slurp output is not valid UTF-8: {}", e))?
        .trim()
        .to_string();

    if geometry.is_empty() {
        return Err("slurp succeeded but returned empty geometry".to_string());
    }

    Command::new("grim")
        .arg("-g")
        .arg(&geometry)
        .arg(path.to_str().unwrap())
        .output()
        .map_err(|e| format!("Failed to execute screencapture: {}", e))
}

/// Takes a screenshot of a selected area and returns the image data as base64
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn take_area_screenshot<R: Runtime>(app: &AppHandle<R>) -> Result<String, String> {
    // Create a temporary file path
    let temp_dir = std::env::temp_dir();
    let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
    let temp_file = temp_dir.join(format!("haystack_screenshot_{}.png", timestamp));

    log::info!("{}", temp_file.display());

    let output = screenshot(&temp_file)?;
    log::info!("0");

    if !output.status.success() {
        return Err(format!(
            "screencapture failed: {}",
            String::from_utf8_lossy(&output.stderr)
        ));
    }

    log::info!("1");

    // Read the captured image
    let contents =
        fs::read(&temp_file).map_err(|e| format!("Failed to read screenshot file: {}", e))?;

    log::info!("2");

    // Convert to base64
    let base64_string = BASE64.encode(&contents);

    // Clean up the temporary file
    if let Err(e) = fs::remove_file(&temp_file) {
        println!("Warning: Failed to remove temporary screenshot file: {}", e);
    }

    app.emit("png-processed", base64_string.clone())
        .map_err(|e| format!("Failed to emit event: {}", e))?;

    Ok(base64_string)
}
