//! `pic apps` subcommands: `ls`, `create`, `show`, `delete`.

use anyhow::Result;
use picloud_shared::AppRole;

use crate::client::{Client, CreateAppBody};
use crate::config;
use crate::output::{KvBlock, OutputMode, Table};

pub async fn ls(mode: OutputMode) -> Result<()> {
    let creds = config::resolve()?;
    let client = Client::from_creds(&creds)?;
    let apps = client.apps_list().await?;
    let mut table = Table::new(["slug", "name", "my_role", "created_at"]);
    for app in apps {
        // The list endpoint returns App without my_role. We do a per-app
        // lookup only on demand; for `ls` we leave the column dashed so
        // the call stays cheap (one HTTP request).
        table.row([
            app.slug.clone(),
            app.name.clone(),
            "-".to_string(),
            app.created_at.to_rfc3339(),
        ]);
    }
    table.print(mode);
    Ok(())
}

pub async fn create(
    slug: &str,
    name: Option<&str>,
    description: Option<&str>,
    group: Option<&str>,
    mode: OutputMode,
) -> Result<()> {
    let creds = config::resolve()?;
    let client = Client::from_creds(&creds)?;
    let body = CreateAppBody {
        slug,
        name: name.unwrap_or(slug),
        description,
        group,
    };
    let app = client.apps_create(&body).await?;
    // Emit the created object so `--output json` callers can capture the
    // id (every later domains/topics/routes call needs it).
    let mut block = KvBlock::new();
    block
        .field("id", app.id.to_string())
        .field("slug", app.slug.clone())
        .field("name", app.name.clone())
        .field(
            "description",
            app.description.clone().unwrap_or_else(|| "-".into()),
        )
        .field("created_at", app.created_at.to_rfc3339());
    block.print(mode);
    Ok(())
}

/// `pic apps show <slug>` — single-app inspect using the lookup
/// endpoint, which carries `my_role` for the caller (the `ls` endpoint
/// doesn't).
pub async fn show(ident: &str, mode: OutputMode) -> Result<()> {
    let creds = config::resolve()?;
    let client = Client::from_creds(&creds)?;
    let lookup = client.apps_get(ident).await?;
    let mut block = KvBlock::new();
    block
        .field("id", lookup.app.id.to_string())
        .field("slug", lookup.app.slug.clone())
        .field("name", lookup.app.name.clone())
        .field(
            "description",
            lookup.app.description.clone().unwrap_or_else(|| "-".into()),
        )
        .field("my_role", role_label(lookup.my_role.as_ref()))
        .field("created_at", lookup.app.created_at.to_rfc3339())
        .field("updated_at", lookup.app.updated_at.to_rfc3339());
    block.print(mode);
    Ok(())
}

/// `pic apps delete <slug> [--force]`. Without `--force` the server
/// returns 409 if the app still owns scripts — surface that as a
/// useful error rather than swallowing.
pub async fn delete(ident: &str, force: bool) -> Result<()> {
    let creds = config::resolve()?;
    let client = Client::from_creds(&creds)?;
    client.apps_delete(ident, force).await?;
    println!("Deleted app {ident}");
    Ok(())
}

fn role_label(role: Option<&AppRole>) -> String {
    // Use the wire form so the CLI label matches what the dashboard
    // shows and what the membership APIs accept.
    match role {
        Some(r) => r.as_str().to_string(),
        None => "-".into(),
    }
}
