//! Marketplace Commands - clap-noun-verb v3.4.0 Migration
//!
//! This module implements marketplace commands using the v3.4.0 #[verb] pattern.

use clap_noun_verb_macros::verb;
use clap_noun_verb::Result;
use serde::Serialize;
use std::path::PathBuf;

use crate::runtime_helper::execute_async_verb;
use ggen_domain::marketplace::{
    SearchInput, execute_search,
    InstallInput, execute_install,
    ListInput, execute_list,
    PublishInput, execute_publish,
};

// ============================================================================
// Output Types
// ============================================================================

#[derive(Serialize)]
struct SearchOutput {
    packages: Vec<PackageInfo>,
    total: usize,
}

#[derive(Serialize)]
struct PackageInfo {
    name: String,
    version: String,
    description: String,
    author: Option<String>,
    downloads: u32,
    stars: u32,
}

#[derive(Serialize)]
struct InstallOutput {
    package: String,
    version: String,
    path: String,
    dependencies: Vec<String>,
}

#[derive(Serialize)]
struct ListOutput {
    packages: Vec<InstalledPackage>,
    total: usize,
}

#[derive(Serialize)]
struct InstalledPackage {
    name: String,
    version: String,
    title: String,
    description: String,
}

#[derive(Serialize)]
struct PublishOutput {
    package: String,
    version: String,
}

// ============================================================================
// Verb Functions
// ============================================================================

/// Search for packages in the marketplace
#[verb]
fn search(
    query: String,
    limit: usize,
    category: Option<String>,
) -> Result<SearchOutput> {
    let input = SearchInput {
        query,
        limit,
        category,
        ..Default::default()
    };

    execute_async_verb(async move {
        let results = execute_search(input).await
            .map_err(|e| clap_noun_verb::NounVerbError::execution_error(e.to_string()))?;

        let packages = results.into_iter().map(|p| PackageInfo {
            name: p.name,
            version: p.version,
            description: p.description,
            author: p.author,
            downloads: p.downloads,
            stars: p.stars,
        }).collect::<Vec<_>>();

        let total = packages.len();

        Ok(SearchOutput { packages, total })
    })
}

/// Install a package from the marketplace
#[verb]
fn install(
    package: String,
    target: Option<String>,
    force: bool,
    no_dependencies: bool,
    dry_run: bool,
) -> Result<InstallOutput> {
    let input = InstallInput {
        package: package.clone(),
        target,
        force,
        no_dependencies,
        dry_run,
    };

    execute_async_verb(async move {
        let result = execute_install(input).await
            .map_err(|e| clap_noun_verb::NounVerbError::execution_error(e.to_string()))?;

        Ok(InstallOutput {
            package: result.package_name,
            version: result.version,
            path: result.install_path.display().to_string(),
            dependencies: result.dependencies_installed,
        })
    })
}

/// List installed packages
#[verb]
fn list(
    detailed: bool,
    json: bool,
) -> Result<ListOutput> {
    let input = ListInput {
        detailed,
        json,
    };

    execute_async_verb(async move {
        let result = execute_list(input).await
            .map_err(|e| clap_noun_verb::NounVerbError::execution_error(e.to_string()))?;

        let packages = result.packages.into_iter().map(|p| InstalledPackage {
            name: p.name,
            version: p.version,
            title: p.title,
            description: p.description,
        }).collect::<Vec<_>>();

        let total = result.packages_listed;

        Ok(ListOutput { packages, total })
    })
}

/// Publish a package to the marketplace
#[verb]
fn publish(
    path: PathBuf,
    tag: Option<String>,
    dry_run: bool,
    force: bool,
) -> Result<PublishOutput> {
    let input = PublishInput {
        path,
        tag,
        dry_run,
        force,
    };

    execute_async_verb(async move {
        let result = execute_publish(input).await
            .map_err(|e| clap_noun_verb::NounVerbError::execution_error(e.to_string()))?;

        Ok(PublishOutput {
            package: result.package_name,
            version: result.version,
        })
    })
}
