use std::path::{Path, PathBuf};
use std::fs;
use std::time::{SystemTime, UNIX_EPOCH};
use tauri::AppHandle;

use crate::models::repository::RepositorySource;
use crate::models::server::ServerInfo;
use crate::services::plugin_scanner::is_file_locked;

/// Backup a plugin before replacing it
pub async fn backup_plugin(plugin_file_path: String) -> Result<String, String> {
    // Get the current timestamp for the backup filename
    let now = SystemTime::now().duration_since(UNIX_EPOCH)
        .map_err(|e| format!("Failed to get timestamp: {}", e))?
        .as_secs();

    // Create backup file path
    let path = Path::new(&plugin_file_path);
    let file_name = path.file_name()
        .ok_or_else(|| "Invalid plugin file path".to_string())?
        .to_str()
        .ok_or_else(|| "Invalid file name encoding".to_string())?;

    // Create backup directory if it doesn't exist
    let backup_dir = path.parent()
        .unwrap_or_else(|| Path::new("."))
        .join("backups");

    if !backup_dir.exists() {
        fs::create_dir_all(&backup_dir)
            .map_err(|e| format!("Failed to create backup directory: {}", e))?;
    }

    // Create backup file path with timestamp
    let backup_path = backup_dir.join(format!("{}.{}.bak", file_name, now));
    let backup_path_str = backup_path.to_string_lossy().to_string();

    // Check if file is locked
    if is_file_locked(&plugin_file_path) {
        return Err(format!("File is locked: {}", plugin_file_path));
    }

    // Copy the file
    fs::copy(&plugin_file_path, &backup_path)
        .map_err(|e| format!("Failed to create backup: {}", e))?;

    Ok(backup_path_str)
}

/// Replace a plugin with a new version
pub async fn replace_plugin(
    plugin_id: String,
    version: String,
    repository: RepositorySource,
    current_file_path: String,
    server_info: Option<ServerInfo>
) -> Result<String, String> {
    // Check if file is locked
    if is_file_locked(&current_file_path) {
        return Err(format!("Plugin file is currently locked: {}", current_file_path));
    }

    // Create a temporary file path
    let download_path = create_temp_download_path(&current_file_path)?;

    // Download the new plugin version
    let server_type = server_info.as_ref().map(|info| &info.server_type);
    crate::lib_download_plugin_from_repository(
        &plugin_id,
        &version,
        repository,
        &download_path.to_string_lossy(),
        server_type
    ).await?;

    // Backup the original file
    backup_plugin(current_file_path.clone()).await?;

    // Replace the original file with the downloaded one
    fs::rename(download_path, &current_file_path)
        .map_err(|e| format!("Failed to replace plugin: {}", e))?;

    Ok(current_file_path)
}

/// Create a temporary file path for plugin download
fn create_temp_download_path(current_file_path: &str) -> Result<PathBuf, String> {
    let path = Path::new(current_file_path);
    let file_stem = path.file_stem()
        .ok_or_else(|| "Invalid plugin file path".to_string())?
        .to_str()
        .ok_or_else(|| "Invalid file name encoding".to_string())?;

    let file_ext = path.extension()
        .unwrap_or_else(|| std::ffi::OsStr::new("jar"))
        .to_str()
        .unwrap_or("jar");

    let parent = path.parent()
        .unwrap_or_else(|| Path::new("."));

    // Generate temp file name with timestamp
    let now = SystemTime::now().duration_since(UNIX_EPOCH)
        .map_err(|e| format!("Failed to get timestamp: {}", e))?
        .as_secs();

    let temp_name = format!("{}.new.{}.{}", file_stem, now, file_ext);
    Ok(parent.join(temp_name))
}