use crate::cli::ProductAction;
use crate::error::Result;
use crate::output::resources::product::{write_product_detail, write_products};
use crate::output::result_types::{write_result, ActionResult, ResourceKind};
use crate::output::writers::Writers;
use crate::types::ApiMode;
use crate::types::OutputFormat;
use crate::types::{CreateProductParams, UpdateProductParams};

pub async fn execute(
    action: &ProductAction,
    server: Option<&str>,
    format: OutputFormat,
    api: Option<ApiMode>,
    w: &mut Writers<'_>,
) -> Result<()> {
    let client = super::shared::connect_and_configure(server, api).await?;

    match action {
        ProductAction::List { r#type } => {
            let products = client.list_products_by_type(*r#type).await?;
            write_products(&products, format, w.out);
        }
        ProductAction::View { name } => {
            let product = client.get_product(name).await?;
            write_product_detail(&product, format, w.out);
        }
        ProductAction::Create {
            name,
            description,
            version,
            is_open,
        } => {
            let params = CreateProductParams {
                name: name.clone(),
                description: description.clone(),
                version: version.clone(),
                is_open: *is_open,
            };
            let id = client.create_product(&params).await?;
            write_result(
                &ActionResult::created_named(id, name.as_str(), ResourceKind::Product),
                &format!("Created product #{id} '{name}'"),
                format,
                w.out,
            );
        }
        ProductAction::Update {
            name,
            description,
            default_milestone,
            is_open,
        } => {
            let params = UpdateProductParams {
                description: description.clone(),
                default_milestone: default_milestone.clone(),
                is_open: *is_open,
            };
            client.update_product(name, &params).await?;
            write_result(
                &ActionResult::updated_named(name.as_str(), None, ResourceKind::Product),
                &format!("Updated product '{name}'"),
                format,
                w.out,
            );
        }
    }
    Ok(())
}

#[cfg(test)]
#[path = "product_tests.rs"]
mod tests;
