use tauri::{command, AppHandle};
use crate::models::repository::RepositorySource;
use crate::models::server::ServerType;
use crate::models::plugin::Plugin;
use crate::services::update_manager::{compare_plugin_versions, backup_plugin, replace_plugin};

/// Search for plugins in specified repositories
#[command]
pub async fn search_plugins(query: String, repositories: Vec<RepositorySource>) -> Result<Vec<crate::models::repository::RepositoryPlugin>, String> {
    crate::lib_search_plugins_in_repositories(&query, repositories).await
}

/// Get plugin details from a repository
#[command]
pub async fn get_plugin_details(
    plugin_id: String,
    repository: RepositorySource,
    server_type_str: Option<String>,
) -> Result<crate::models::repository::RepositoryPlugin, String> {
    // Convert server_type_str to ServerType if provided
    let server_type = if let Some(type_str) = server_type_str {
        match type_str.as_str() {
            "paper" => Some(crate::models::server::ServerType::Paper),
            "spigot" => Some(crate::models::server::ServerType::Spigot),
            "bukkit" => Some(crate::models::server::ServerType::Bukkit),
            "velocity" => Some(crate::models::server::ServerType::Velocity),
            "bungeecord" => Some(crate::models::server::ServerType::BungeeCord),
            "waterfall" => Some(crate::models::server::ServerType::Waterfall),
            "forge" => Some(crate::models::server::ServerType::Forge),
            "fabric" => Some(crate::models::server::ServerType::Fabric),
            _ => None,
        }
    } else {
        None
    };

    crate::lib_get_plugin_details_from_repository(&plugin_id, repository, server_type.as_ref()).await
}

/// Download a plugin from a repository
#[command]
pub async fn download_plugin(
    plugin_id: String,
    version: String,
    repository: String,
    destination: String,
    server_type_str: Option<String>
) -> Result<String, String> {
    // Convert repository string to RepositorySource
    let repo_source = match repository.to_lowercase().as_str() {
        "hangarmc" => RepositorySource::HangarMC,
        "spigotmc" => RepositorySource::SpigotMC,
        "modrinth" => RepositorySource::Modrinth,
        "github" => RepositorySource::GitHub,
        "bukkitdev" => RepositorySource::BukkitDev,
        _ => RepositorySource::Custom(repository.clone()),
    };

    // Convert server_type_str to ServerType if provided
    let server_type = if let Some(type_str) = server_type_str {
        match type_str.as_str() {
            "paper" => Some(ServerType::Paper),
            "spigot" => Some(ServerType::Spigot),
            "bukkit" => Some(ServerType::Bukkit),
            "velocity" => Some(ServerType::Velocity),
            "bungeecord" => Some(ServerType::BungeeCord),
            "waterfall" => Some(ServerType::Waterfall),
            "forge" => Some(ServerType::Forge),
            "fabric" => Some(ServerType::Fabric),
            _ => None,
        }
    } else {
        None
    };

    crate::lib_download_plugin_from_repository(&plugin_id, &version, repo_source, &destination, server_type.as_ref()).await
}

/// Update a plugin with a new version
#[command]
pub async fn update_plugin(
    app_handle: AppHandle,
    plugin_id: String,
    version: String,
    repository: String,
    current_file_path: String,
    server_type_str: Option<String>
) -> Result<String, String> {
    // Convert repository string to RepositorySource
    let repo_source = match repository.to_lowercase().as_str() {
        "hangarmc" => RepositorySource::HangarMC,
        "spigotmc" => RepositorySource::SpigotMC,
        "modrinth" => RepositorySource::Modrinth,
        "github" => RepositorySource::GitHub,
        "bukkitdev" => RepositorySource::BukkitDev,
        _ => RepositorySource::Custom(repository.clone()),
    };

    // Convert server_type_str to ServerInfo if provided
    let server_info = if let Some(type_str) = server_type_str {
        let server_type = match type_str.as_str() {
            "paper" => ServerType::Paper,
            "spigot" => ServerType::Spigot,
            "bukkit" => ServerType::Bukkit,
            "velocity" => ServerType::Velocity,
            "bungeecord" => ServerType::BungeeCord,
            "waterfall" => ServerType::Waterfall,
            "forge" => ServerType::Forge,
            "fabric" => ServerType::Fabric,
            _ => ServerType::Unknown,
        };

        Some(crate::models::server::ServerInfo {
            server_type,
            minecraft_version: None,
            plugins_directory: "".to_string(),
            plugins_count: 0,
        })
    } else {
        None
    };

    // Replace the plugin
    replace_plugin(plugin_id, version, repo_source, current_file_path, server_info).await
}

/// Check for updates for multiple plugins
#[command]
pub async fn check_plugin_updates(
    app_handle: AppHandle,
    plugins: Vec<Plugin>,
    repositories: Vec<String>
) -> Result<Vec<Plugin>, String> {
    // Convert repository strings to RepositorySource
    let repos: Vec<RepositorySource> = repositories.into_iter()
        .map(|repo| match repo.to_lowercase().as_str() {
            "hangarmc" => RepositorySource::HangarMC,
            "spigotmc" => RepositorySource::SpigotMC,
            "modrinth" => RepositorySource::Modrinth,
            "github" => RepositorySource::GitHub,
            "bukkitdev" => RepositorySource::BukkitDev,
            _ => RepositorySource::Custom(repo),
        })
        .collect();

    crate::services::update_manager::check_for_plugin_updates(app_handle, plugins, repos).await
}

/// Check for updates for a single plugin
#[command]
pub async fn check_single_plugin_update_command(
    app_handle: AppHandle,
    plugin: Plugin,
    repositories: Vec<String>
) -> Result<(), String> {
    // Convert repository strings to RepositorySource
    let repos: Vec<RepositorySource> = repositories.into_iter()
        .map(|repo| match repo.to_lowercase().as_str() {
            "hangarmc" => RepositorySource::HangarMC,
            "spigotmc" => RepositorySource::SpigotMC,
            "modrinth" => RepositorySource::Modrinth,
            "github" => RepositorySource::GitHub,
            "bukkitdev" => RepositorySource::BukkitDev,
            _ => RepositorySource::Custom(repo),
        })
        .collect();

    crate::services::update_manager::check_single_plugin_update(app_handle, plugin, repos).await
}

/// Create a backup of a plugin file
#[command]
pub async fn backup_plugin_command(plugin_file_path: String) -> Result<String, String> {
    backup_plugin(plugin_file_path).await
}

/// Set repository source for a plugin
#[command]
pub async fn set_plugin_repository(
    app_handle: AppHandle,
    plugin_file_path: String,
    repository: String,
    repository_id: String,
    page_url: String,
    server_path: String
) -> Result<Plugin, String> {
    // Convert repository string to RepositorySource
    let repo_source = match repository.to_lowercase().as_str() {
        "hangarmc" => RepositorySource::HangarMC,
        "spigotmc" => RepositorySource::SpigotMC,
        "modrinth" => RepositorySource::Modrinth,
        "github" => RepositorySource::GitHub,
        "bukkitdev" => RepositorySource::BukkitDev,
        _ => RepositorySource::Custom(repository.clone()),
    };

    // Load the plugin data
    let plugins = crate::services::plugin_scanner::perform_scan(&app_handle, &server_path).await?.plugins;

    // Find the specific plugin
    let mut plugin = plugins.into_iter()
        .find(|p| p.file_path == plugin_file_path)
        .ok_or_else(|| format!("Plugin not found: {}", plugin_file_path))?;

    // Update repository information
    plugin.repository_source = Some(repo_source);
    plugin.repository_id = Some(repository_id);
    plugin.repository_url = Some(page_url);

    // Trigger an update check
    if let Some(repo_id) = &plugin.repository_id {
        if let Some(repo_source) = &plugin.repository_source {
            match crate::lib_get_plugin_details_from_repository(repo_id, repo_source.clone(), None).await {
                Ok(repo_plugin) => {
                    // Set latest version if newer
                    if repo_plugin.version != plugin.version {
                        let has_update = compare_plugin_versions(&plugin.version, &repo_plugin.version);
                        plugin.latest_version = Some(repo_plugin.version);
                        plugin.has_update = has_update;
                        plugin.changelog = repo_plugin.changelog;
                    } else {
                        plugin.has_update = false;
                    }
                },
                Err(e) => {
                    println!("Error checking for updates: {}", e);
                }
            }
        }
    }

    Ok(plugin)
}

/// Load saved plugin data for a specific server
#[command]
pub async fn load_plugin_data(
    app_handle: AppHandle,
    server_path: String,
) -> Result<Vec<Plugin>, String> {
    let data_dir = crate::services::plugin_scanner::get_plugin_data_path(&app_handle, &server_path)?;
    let data_path = data_dir.join("plugins.json");

    if !data_path.exists() {
        // If the file doesn't exist, it's not an error, just return empty list
        return Ok(Vec::new());
    }

    // Read the file content
    let json_data = std::fs::read_to_string(&data_path)
        .map_err(|e| format!("Failed to read plugin data file: {}", e))?;

    // Deserialize the JSON data
    let plugins: Vec<Plugin> = serde_json::from_str(&json_data)
        .map_err(|e| format!("Failed to deserialize plugin data: {}", e))?;

    Ok(plugins)
}

/// Save plugin data for a specific server
#[command]
pub async fn save_plugin_data(
    app_handle: AppHandle,
    plugins: Vec<Plugin>,
    server_path: String,
) -> Result<(), String> {
    let data_dir = crate::services::plugin_scanner::get_plugin_data_path(&app_handle, &server_path)?;

    // Create directory if it doesn't exist
    if !data_dir.exists() {
        std::fs::create_dir_all(&data_dir)
            .map_err(|e| format!("Failed to create plugin data directory: {}", e))?;
    }

    // Save plugins data
    let data_path = data_dir.join("plugins.json");
    let json_data = serde_json::to_string_pretty(&plugins)
        .map_err(|e| format!("Failed to serialize plugin data for saving: {}", e))?;

    std::fs::write(&data_path, json_data)
        .map_err(|e| format!("Failed to write plugin data file: {}", e))?;

    Ok(())
}

/// Get versions for a plugin from a repository
#[command]
pub async fn get_plugin_versions(
    plugin_id: String,
    repository: String
) -> Result<Vec<String>, String> {
    // This is a placeholder - would need to implement the actual repository API call
    Ok(vec!["1.0.0".to_string(), "1.1.0".to_string(), "1.2.0".to_string()])
}

/// Get potential matches for a plugin from repositories
#[command]
pub async fn get_potential_plugin_matches(
    app_handle: AppHandle,
    plugin: Plugin,
    repositories: Vec<String>
) -> Result<Vec<crate::models::repository::PotentialPluginMatch>, String> {
    // Convert repository strings to RepositorySource
    let repos: Vec<RepositorySource> = repositories.into_iter()
        .map(|repo| match repo.to_lowercase().as_str() {
            "hangarmc" => RepositorySource::HangarMC,
            "spigotmc" => RepositorySource::SpigotMC,
            "modrinth" => RepositorySource::Modrinth,
            "github" => RepositorySource::GitHub,
            "bukkitdev" => RepositorySource::BukkitDev,
            _ => RepositorySource::Custom(repo),
        })
        .collect();

    // This is a placeholder - would need to implement actual search
    Ok(Vec::new())
}

/// Compare two version strings
#[command]
pub fn compare_versions(version1: String, version2: String) -> bool {
    compare_plugin_versions(&version1, &version2)
}

/// Check if a plugin is compatible with a specific Minecraft version
#[command]
pub fn is_plugin_compatible(plugin_version: String, minecraft_version: String) -> bool {
    // This is a placeholder - would need to implement actual compatibility check
    true
}

/// Simple greeting function for testing
#[command]
pub fn greet(name: &str) -> String {
    format!("Hello, {}! Welcome to PlugSnatcher.", name)
}