// 数据库备份与恢复模块
// v2 - 恢复后自动完成数据库迁移，无需重启
use std::fs;
use std::path::Path;
use chrono::Local;


/// 备份数据库到 backup 目录
#[tauri::command]
pub fn backup_database(username: String) -> Result<String, String> {
    if !crate::permissions::check_permission(&username, "logs_view") {
        return Err("权限不足：没有备份数据库的权限".to_string());
    }
    let db_path = "inventory.db";
    if !Path::new(db_path).exists() {
        return Err("数据库文件不存在".to_string());
    }
    
    // 创建备份目录
    let backup_dir = "backups";
    let _ = fs::create_dir_all(backup_dir);
    
    let timestamp = Local::now().format("%Y%m%d_%H%M%S").to_string();
    let backup_path = format!("{}/inventory_backup_{}.db", backup_dir, timestamp);
    
    fs::copy(db_path, &backup_path).map_err(|e| format!("备份失败: {}", e))?;
    
    Ok(format!("备份成功: inventory_backup_{}.db", timestamp))
}

/// 列出所有备份文件
#[tauri::command]
pub fn list_backups() -> Result<Vec<serde_json::Value>, String> {
    let backup_dir = "backups";
    let _ = fs::create_dir_all(backup_dir);
    
    let mut backups = Vec::new();
    if let Ok(entries) = fs::read_dir(backup_dir) {
        for entry in entries.flatten() {
            let path = entry.path();
            if let Some(ext) = path.extension() {
                if ext == "db" {
                    let name = path.file_name().unwrap().to_string_lossy().to_string();
                    let size = fs::metadata(&path).map(|m| m.len()).unwrap_or(0);
                    let time = fs::metadata(&path).and_then(|m| m.modified()).ok()
                        .map(|t| {
                            let dt: chrono::DateTime<Local> = t.into();
                            dt.format("%Y-%m-%d %H:%M:%S").to_string()
                        }).unwrap_or_default();
                    backups.push(serde_json::json!({
                        "name": name,
                        "size": size,
                        "created_at": time,
                    }));
                }
            }
        }
    }
    // 按文件名倒序（最新的在前）
    backups.sort_by(|a, b| b["name"].as_str().unwrap_or("").cmp(a["name"].as_str().unwrap_or("")));
    Ok(backups)
}

/// 保存备份到指定路径（用户选择的目录/文件名）
#[tauri::command]
pub fn save_backup_to(path: String, username: String) -> Result<String, String> {
    if !crate::permissions::check_permission(&username, "logs_view") {
        return Err("权限不足：没有备份数据库的权限".to_string());
    }
    let db_path = "inventory.db";
    if !Path::new(db_path).exists() {
        return Err("数据库文件不存在".to_string());
    }
    // 确保目录存在
    if let Some(parent) = Path::new(&path).parent() {
        let _ = fs::create_dir_all(parent);
    }
    fs::copy(db_path, &path).map_err(|e| format!("保存备份失败: {}", e))?;
    
    // 记住本次路径
    let _ = save_last_path(&path);
    
    // 同时在 backups/ 目录也留一份
    let _ = fs::create_dir_all("backups");
    let timestamp = Local::now().format("%Y%m%d_%H%M%S").to_string();
    let local_copy = format!("backups/inventory_backup_{}.db", timestamp);
    let _ = fs::copy(db_path, &local_copy);
    
    Ok(format!("备份成功！文件已保存到:\n{}", path))
}

/// 从任意路径恢复数据库（支持用户选择的备份文件）
#[tauri::command]
pub fn restore_database_from(path: String, username: String) -> Result<String, String> {
    if !crate::permissions::check_permission(&username, "logs_view") {
        return Err("权限不足：没有恢复数据库的权限".to_string());
    }
    if !Path::new(&path).exists() {
        return Err(format!("备份文件不存在: {}", path));
    }
    
    let db_path = "inventory.db";
    
    // ========== 第一步：关闭当前数据库连接 ==========
    let mut conn_guard = crate::database::DB_CONN.lock()
        .map_err(|e| format!("无法获取数据库锁: {}", e))?;
    *conn_guard = None;
    drop(conn_guard);
    
    // ========== 第二步：备份当前数据库（防止恢复失败）==========
    let temp_backup = "inventory_before_restore.db";
    let _ = fs::copy(db_path, temp_backup);
    
    // ========== 第三步：恢复备份文件 ==========
    if let Err(e) = fs::copy(&path, db_path) {
        let _ = fs::copy(temp_backup, db_path);
        let _ = fs::remove_file(temp_backup);
        return Err(format!("恢复失败: {}", e));
    }
    
    // ========== 第四步：验证数据库完整性 ==========
    match check_db_integrity(db_path) {
        Ok(_) => {}
        Err(e) => {
            let _ = fs::copy(temp_backup, db_path);
            let _ = fs::remove_file(temp_backup);
            return Err(format!("备份文件损坏，数据库完整性校验失败: {}", e));
        }
    }
    
    let _ = fs::remove_file(temp_backup);
    
    // ========== 第五步：重新初始化数据库（自动迁移）==========
    crate::database::init_db()?;
    
    // ========== 第六步：Schema 完整性校验 ==========
    let validation_conn = crate::database::DB_CONN.lock()
        .map_err(|e| format!("无法获取数据库连接: {}", e))?;
    let valid_ref = validation_conn.as_ref()
        .ok_or("数据库连接未初始化")?;
    let checks = crate::database::validate_schema(valid_ref)?;
    drop(validation_conn);
    
    let summary = checks.iter().map(|s| format!("  ✅ {}", s)).collect::<Vec<_>>().join("\n");
    
    Ok(format!(
        "✅ 数据库恢复并升级成功！\n\n校验详情：\n{}",
        summary
    ))
}

/// 获取上一次备份/恢复的路径
#[tauri::command]
pub fn get_last_backup_path() -> Result<String, String> {
    let conn_guard = crate::database::DB_CONN.lock()
        .map_err(|e| e.to_string())?;
    let conn = conn_guard.as_ref().ok_or("数据库未初始化")?;
    let result: Result<String, _> = conn.query_row(
        "SELECT config_value FROM system_config WHERE config_key = 'last_backup_path'",
        [], |row| row.get(0)
    );
    match result {
        Ok(val) => Ok(val),
        Err(_) => Ok(String::new()),
    }
}

/// 保存本次备份路径到系统配置
fn save_last_path(path: &str) -> Result<(), String> {
    let conn_guard = crate::database::DB_CONN.lock().map_err(|e| e.to_string())?;
    if let Some(conn) = conn_guard.as_ref() {
        let exists: i64 = conn.query_row(
            "SELECT COUNT(*) FROM system_config WHERE config_key = 'last_backup_path'",
            [], |row| row.get(0)
        ).unwrap_or(0);
        if exists > 0 {
            let _ = conn.execute(
                "UPDATE system_config SET config_value = ?1, updated_at = datetime('now','localtime') WHERE config_key = 'last_backup_path'",
                [path]
            );
        } else {
            let _ = conn.execute(
                "INSERT INTO system_config (id, config_key, config_value, description, updated_at) VALUES (?1,'last_backup_path',?2,'上次备份路径',datetime('now','localtime'))",
                [&uuid::Uuid::new_v4().to_string(), path]
            );
        }
    }
    Ok(())
}

/// 从备份文件恢复数据库（兼容旧版 — 从 backups/ 目录读取），完成后自动运行迁移
#[tauri::command]
pub fn restore_database(backup_name: String, username: String) -> Result<String, String> {
    if !crate::permissions::check_permission(&username, "logs_view") {
        return Err("权限不足：没有恢复数据库的权限".to_string());
    }
    let backup_path = format!("backups/{}", backup_name);
    restore_database_from(backup_path, username)
}

/// 重启整个应用程序（自启动新进程 → 退出当前进程）
/// 调用此命令后前台看不到返回值，因为进程会立即退出
#[tauri::command]
pub fn restart_app(app_handle: tauri::AppHandle, username: String) -> Result<(), String> {
    if !crate::permissions::check_permission(&username, "logs_view") {
        return Err("权限不足：没有重启应用的权限".to_string());
    }
    let exe = std::env::current_exe()
        .map_err(|e| format!("获取程序路径失败: {}", e))?;
    
    // 先启动一个新实例，再退出当前进程
    std::process::Command::new(&exe)
        .spawn()
        .map_err(|e| format!("启动新程序实例失败: {}", e))?;
    
    // 正常关闭当前应用，让新进程接管
    app_handle.exit(0);
    
    // 不会执行到这里
    Ok(())
}


// ==================== 自动备份 ====================

/// 检查并执行自动备份（前端定时调用 + 启动时调用）
#[tauri::command]
pub fn check_and_run_auto_backup() -> Result<String, String> {
    // 读取自动备份配置
    let conn_guard = crate::database::DB_CONN.lock()
        .map_err(|e| format!("数据库锁获取失败: {}", e))?;
    let conn = conn_guard.as_ref().ok_or("数据库未初始化")?;

    let enabled: String = conn.query_row(
        "SELECT config_value FROM system_config WHERE config_key='auto_backup_enabled'",
        [], |row| row.get(0)
    ).unwrap_or_else(|_| "0".to_string());

    if enabled != "1" {
        return Ok("自动备份未启用".to_string());
    }

    let frequency: String = conn.query_row(
        "SELECT config_value FROM system_config WHERE config_key='auto_backup_frequency'",
        [], |row| row.get(0)
    ).unwrap_or_else(|_| "daily".to_string());

    let last_backup: String = conn.query_row(
        "SELECT config_value FROM system_config WHERE config_key='last_auto_backup'",
        [], |row| row.get(0)
    ).unwrap_or_else(|_| String::new());

    drop(conn_guard);

    // 判断是否需要备份
    let now = Local::now().naive_local();
    let need_backup = if last_backup.is_empty() {
        true // 从未自动备份过，立即备份
    } else {
        if let Ok(last_time) = chrono::NaiveDateTime::parse_from_str(&last_backup, "%Y-%m-%d %H:%M:%S") {
            let duration = now.signed_duration_since(last_time);
            let days_passed = duration.num_days();
            match frequency.as_str() {
                "daily" => days_passed >= 1,
                "weekly" => days_passed >= 7,
                "monthly" => days_passed >= 30,
                "quarterly" => days_passed >= 90,
                _ => days_passed >= 1,
            }
        } else {
            true // 时间解析失败，执行备份
        }
    };

    if !need_backup {
        return Ok("未到备份时间".to_string());
    }

    // 执行备份
    let db_path = "inventory.db";
    if !Path::new(db_path).exists() {
        return Err("数据库文件不存在".to_string());
    }

    let _ = fs::create_dir_all("backups");
    let timestamp = now.format("%Y%m%d_%H%M%S").to_string();
    let backup_path = format!("backups/auto_backup_{}.db", timestamp);

    fs::copy(db_path, &backup_path)
        .map_err(|e| format!("自动备份失败: {}", e))?;

    // 更新最后备份时间
    let time_str = now.format("%Y-%m-%d %H:%M:%S").to_string();
    let conn_guard2 = crate::database::DB_CONN.lock()
        .map_err(|e| format!("数据库锁获取失败: {}", e))?;
    if let Some(conn2) = conn_guard2.as_ref() {
        let exists: i64 = conn2.query_row(
            "SELECT COUNT(*) FROM system_config WHERE config_key='last_auto_backup'",
            [], |row| row.get(0)
        ).unwrap_or(0);
        if exists > 0 {
            let _ = conn2.execute(
                "UPDATE system_config SET config_value=?1, updated_at=datetime('now','localtime') WHERE config_key='last_auto_backup'",
                [&time_str]
            );
        } else {
            let _ = conn2.execute(
                "INSERT INTO system_config (id, config_key, config_value, description, updated_at) VALUES (?1,'last_auto_backup',?2,'上次自动备份时间',datetime('now','localtime'))",
                [&uuid::Uuid::new_v4().to_string(), &time_str]
            );
        }
    }

    Ok(format!("自动备份完成: auto_backup_{}.db", timestamp))
}

/// 获取自动备份配置
#[tauri::command]
pub fn get_auto_backup_config() -> Result<serde_json::Value, String> {
    let conn_guard = crate::database::DB_CONN.lock()
        .map_err(|e| format!("数据库锁获取失败: {}", e))?;
    let conn = conn_guard.as_ref().ok_or("数据库未初始化")?;

    let enabled = conn.query_row(
        "SELECT config_value FROM system_config WHERE config_key='auto_backup_enabled'",
        [], |row| row.get::<_, String>(0)
    ).unwrap_or_else(|_| "0".to_string());

    let frequency = conn.query_row(
        "SELECT config_value FROM system_config WHERE config_key='auto_backup_frequency'",
        [], |row| row.get::<_, String>(0)
    ).unwrap_or_else(|_| "daily".to_string());

    let last_backup = conn.query_row(
        "SELECT config_value FROM system_config WHERE config_key='last_auto_backup'",
        [], |row| row.get::<_, String>(0)
    ).unwrap_or_else(|_| String::new());

    Ok(serde_json::json!({
        "enabled": enabled == "1",
        "frequency": frequency,
        "last_backup": last_backup,
    }))
}

/// 使用 PRAGMA integrity_check 验证数据库文件完整性
fn check_db_integrity(db_path: &str) -> Result<(), String> {
    let conn = rusqlite::Connection::open(db_path)
        .map_err(|e| format!("无法打开数据库文件验证: {}", e))?;
    
    let mut stmt = conn.prepare("PRAGMA integrity_check")
        .map_err(|e| format!("PRAGMA 准备失败: {}", e))?;
    
    let result: String = stmt.query_row([], |row| row.get(0))
        .map_err(|e| format!("PRAGMA 执行失败: {}", e))?;
    
    if result != "ok" {
        return Err(format!("数据库完整性检测异常: {}", result));
    }
    
    Ok(())
}
