use std::path::PathBuf;
use std::fs;
use tauri::{Manager, path::BaseDirectory, WindowEvent, PhysicalPosition, PhysicalSize};
use serde::{Serialize, Deserialize};

/// Templates directory name
const TEMPLATES_DIR_NAME: &str = "templates";

/// Template info for frontend
#[derive(Serialize, Deserialize)]
struct TemplateFile {
    name: String,
    content: String,
    category: String, // Folder name (e.g., "academic", "corporate")
}

/// Debug command to check path resolution
#[tauri::command]
fn debug_paths(app: tauri::AppHandle) -> Result<String, String> {
    let mut output = String::new();
    
    // Check executable directory using std::env (reliable)
    let exe_dir = get_exe_dir(&app);
    match exe_dir {
        Some(ref p) => output.push_str(&format!("Executable dir (std::env): {:?}\n", p)),
        None => output.push_str("Executable dir: failed to get\n"),
    }
    
    // Check resource directory
    match app.path().resolve("", BaseDirectory::Resource) {
        Ok(p) => output.push_str(&format!("Resource dir: {:?}\n", p)),
        Err(e) => output.push_str(&format!("Resource dir error: {}\n", e)),
    }
    
    // Check if templates exist in exe location
    if let Some(ref exe_dir) = exe_dir {
        let templates_exe = exe_dir.join("templates");
        output.push_str(&format!("Templates path ({:?}): exists={}\n", templates_exe, templates_exe.exists()));
        
        if templates_exe.exists() {
            match fs::read_dir(&templates_exe) {
                Ok(entries) => {
                    output.push_str("  Contents:\n");
                    for entry in entries.flatten() {
                        output.push_str(&format!("    {:?}\n", entry.path()));
                    }
                }
                Err(e) => output.push_str(&format!("  Error reading: {}\n", e)),
            }
        }
    }
    
    Ok(output)
}

/// Get the absolute path to the templates directory
#[tauri::command]
fn get_templates_dir(app: tauri::AppHandle) -> Result<String, String> {
    let exe_dir = get_exe_dir(&app)
        .ok_or("Failed to get executable directory")?;
    let templates_dir = exe_dir.join("templates");
    Ok(templates_dir.to_string_lossy().to_string())
}

/// Read all template files from the templates directory
#[tauri::command]
fn read_templates(app: tauri::AppHandle) -> Result<Vec<TemplateFile>, String> {
    let exe_dir = get_exe_dir(&app)
        .ok_or("Failed to get executable directory")?;
    let templates_dir = exe_dir.join(TEMPLATES_DIR_NAME);
    
    println!("Reading templates from: {:?}", templates_dir);
    
    let mut templates = Vec::new();
    
    if !templates_dir.exists() {
        println!("Templates dir doesn't exist, trying to extract...");
        // Try to extract templates first
        extract_templates_on_first_run(&app)
            .map_err(|e| format!("Failed to extract templates: {}", e))?;
    }
    
    if templates_dir.exists() {
        println!("Templates dir exists, reading recursively...");
        read_templates_recursive(&templates_dir, &mut templates, &templates_dir)
            .map_err(|e| format!("Failed to read templates: {}", e))?;
        println!("Found {} templates", templates.len());
    } else {
        println!("Templates dir still doesn't exist after extraction attempt");
    }
    
    Ok(templates)
}

/// Recursively read all .json template files
fn read_templates_recursive(
    dir: &PathBuf, 
    templates: &mut Vec<TemplateFile>,
    base_dir: &PathBuf
) -> Result<(), Box<dyn std::error::Error>> {
    for entry in fs::read_dir(dir)? {
        let entry = entry?;
        let path = entry.path();
        let name = entry.file_name().to_string_lossy().to_string();
        
        if path.is_dir() {
            read_templates_recursive(&path, templates, base_dir)?;
        } else if name.ends_with(".json") {
            let content = fs::read_to_string(&path)?;
            // Extract category from the relative path (folder name)
            let category = path.parent()
                .and_then(|p| p.strip_prefix(base_dir).ok())
                .and_then(|p| p.components().next())
                .map(|c| c.as_os_str().to_string_lossy().to_string())
                .unwrap_or_else(|| "Other".to_string());
            
            templates.push(TemplateFile { name, content, category });
        }
    }
    Ok(())
}

/// Open the templates folder in file explorer
#[tauri::command]
fn open_templates_folder(app: tauri::AppHandle) -> Result<(), String> {
    let exe_dir = get_exe_dir(&app)
        .ok_or("Failed to get executable directory")?;
    let templates_dir = exe_dir.join(TEMPLATES_DIR_NAME);
    
    // Create if doesn't exist
    if !templates_dir.exists() {
        fs::create_dir_all(&templates_dir)
            .map_err(|e| format!("Failed to create templates dir: {}", e))?;
    }
    
    // Open with default application using opener crate
    opener::open(&templates_dir)
        .map_err(|e| format!("Failed to open folder: {}", e))?;
    
    Ok(())
}

/// Toggle DevTools for the main window
#[tauri::command]
fn toggle_devtools(app: tauri::AppHandle) -> Result<bool, String> {
    if let Some(window) = app.get_webview_window("main") {
        let is_open = window.is_devtools_open();
        
        if is_open {
            window.close_devtools();
        } else {
            window.open_devtools();
        }
        
        return Ok(!is_open);
    }
    Err("Main window not found".to_string())
}

/// Window state structure
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
struct WindowState {
    x: i32,
    y: i32,
    width: u32,
    height: u32,
    maximized: bool,
}

/// Gets the executable directory using std::env (more reliable than BaseDirectory::Executable on Windows)
fn get_exe_dir(_app: &tauri::AppHandle) -> Option<PathBuf> {
    std::env::current_exe()
        .ok()
        .and_then(|p| p.parent().map(|p| p.to_path_buf()))
}

/// Extract bundled templates to the executable directory on first run
fn extract_templates_on_first_run(app: &tauri::AppHandle) -> Result<(), Box<dyn std::error::Error>> {
    let exe_dir = get_exe_dir(app).ok_or("Failed to get executable directory")?;
    let templates_target = exe_dir.join(TEMPLATES_DIR_NAME);
    
    // Check if templates already exist (first run detection)
    if templates_target.exists() {
        return Ok(());
    }
    
    println!("First run detected. Extracting templates...");
    
    // Get bundled templates resource path
    let resource_path = app.path().resolve(TEMPLATES_DIR_NAME, BaseDirectory::Resource)?;
    
    if !resource_path.exists() {
        println!("Warning: Bundled templates not found at: {:?}", resource_path);
        return Ok(());
    }
    
    // Create templates directory
    fs::create_dir_all(&templates_target)?;
    
    // Copy all template files recursively
    copy_dir_recursive(&resource_path, &templates_target)?;
    
    println!("Templates extracted successfully to: {:?}", templates_target);
    Ok(())
}

/// Recursively copy directory contents
fn copy_dir_recursive(src: &PathBuf, dst: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
    fs::create_dir_all(dst)?;
    
    for entry in fs::read_dir(src)? {
        let entry = entry?;
        let path = entry.path();
        let file_name = entry.file_name();
        let dest_path = dst.join(&file_name);
        
        if path.is_dir() {
            copy_dir_recursive(&path, &dest_path)?;
        } else {
            fs::copy(&path, &dest_path)?;
        }
    }
    
    Ok(())
}

/// Get the window state file path
fn get_state_file_path(app: &tauri::AppHandle) -> PathBuf {
    let exe_dir = get_exe_dir(app).unwrap_or_else(|| PathBuf::from("."));
    exe_dir.join("window-state.json")
}

/// Load window state
fn load_window_state(app: &tauri::AppHandle) -> Option<WindowState> {
    let state_file = get_state_file_path(app);
    if state_file.exists() {
        if let Ok(data) = std::fs::read_to_string(&state_file) {
            if let Ok(state) = serde_json::from_str::<WindowState>(&data) {
                return Some(state);
            }
        }
    }
    None
}

/// Save window state
fn save_window_state(app: &tauri::AppHandle, state: &WindowState) {
    let state_file = get_state_file_path(app);
    if let Ok(json) = serde_json::to_string(state) {
        let _ = std::fs::write(&state_file, json);
    }
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_fs::init())
        .plugin(tauri_plugin_store::Builder::default().build())
        .plugin(tauri_plugin_http::init())
        .plugin(tauri_plugin_shell::init())
        .plugin(tauri_plugin_opener::init())
        .setup(|app| {
            // Extract templates on first run
            if let Err(e) = extract_templates_on_first_run(&app.handle()) {
                eprintln!("Failed to extract templates: {}", e);
            }
            
            // Load and apply window state BEFORE showing window
            if let Some(window) = app.get_webview_window("main") {
                if let Some(state) = load_window_state(&app.handle()) {
                    if state.maximized {
                        let _ = window.maximize();
                    } else {
                        let _ = window.set_size(tauri::Size::Physical(
                            PhysicalSize { width: state.width, height: state.height }
                        ));
                        let _ = window.set_position(tauri::Position::Physical(
                            PhysicalPosition { x: state.x, y: state.y }
                        ));
                    }
                }
                
                let _ = window.show();
                let _ = window.set_focus();
            }

            Ok(())
        })
        .on_window_event(|window, event| {
            match event {
                WindowEvent::Moved(position) => {
                    let app_handle = window.app_handle().clone();
                    let pos = *position;
                    let size = window.inner_size().unwrap_or(PhysicalSize { width: 1400, height: 900 });
                    let maximized = window.is_maximized().unwrap_or(false);
                    
                    let state = WindowState {
                        x: pos.x,
                        y: pos.y,
                        width: size.width,
                        height: size.height,
                        maximized,
                    };
                    save_window_state(&app_handle, &state);
                }
                WindowEvent::Resized(size) => {
                    let app_handle = window.app_handle().clone();
                    let pos = window.outer_position().unwrap_or(PhysicalPosition { x: 0, y: 0 });
                    let maximized = window.is_maximized().unwrap_or(false);
                    
                    let state = WindowState {
                        x: pos.x,
                        y: pos.y,
                        width: size.width,
                        height: size.height,
                        maximized,
                    };
                    save_window_state(&app_handle, &state);
                }
                _ => {}
            }
        })
        .invoke_handler(tauri::generate_handler![
            debug_paths,
            get_templates_dir,
            read_templates,
            open_templates_folder,
            toggle_devtools
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
