//! `pic vars ls | set | rm` — manage Phase-3 group/app config vars.
//!
//! Wraps `/api/v1/admin/{apps,groups}/{id}/vars*`. Exactly one of
//! `--group` / `--app` selects the owner. `ls` shows the owner's OWN rows
//! (not the resolved/inherited view). Set values are JSON strings by
//! default; `--json` parses the value as raw JSON.

use anyhow::{anyhow, Result};

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

/// Resolve the `--group`/`--app` pair into exactly one owner (shared XOR
/// message via [`crate::cmds::require_one_owner`]).
fn owner<'a>(group: Option<&'a str>, app: Option<&'a str>) -> Result<VarOwnerArg<'a>> {
    Ok(match crate::cmds::require_one_owner(app, group)? {
        crate::cmds::OwnerRef::App(a) => VarOwnerArg::App(a),
        crate::cmds::OwnerRef::Group(g) => VarOwnerArg::Group(g),
    })
}

pub async fn ls(group: Option<&str>, app: Option<&str>, mode: OutputMode) -> Result<()> {
    let owner = owner(group, app)?;
    let creds = config::resolve()?;
    let client = Client::from_creds(&creds)?;
    let resp = client.vars_list(owner).await?;
    let mut table = Table::new(["key", "env", "value", "tombstone", "updated_at"]);
    for v in resp.vars {
        table.row([
            v.key,
            v.env,
            v.value.to_string(),
            v.is_tombstone.to_string(),
            v.updated_at.to_rfc3339(),
        ]);
    }
    table.print(mode);
    Ok(())
}

pub async fn set(
    group: Option<&str>,
    app: Option<&str>,
    key: &str,
    value: &str,
    env: Option<&str>,
    as_json: bool,
    tombstone: bool,
) -> Result<()> {
    let owner = owner(group, app)?;
    let creds = config::resolve()?;
    let client = Client::from_creds(&creds)?;
    // A tombstone carries no value (the server stores JSON null + the
    // deletion marker); otherwise parse per `--json`.
    let parsed = if tombstone {
        serde_json::Value::Null
    } else if as_json {
        serde_json::from_str(value).map_err(|e| anyhow!("parse value as JSON: {e}"))?
    } else {
        serde_json::Value::String(value.to_string())
    };
    client.vars_set(owner, key, parsed, env, tombstone).await?;
    if tombstone {
        println!("Set tombstone for {key}");
    } else {
        println!("Set var {key}");
    }
    Ok(())
}

pub async fn rm(
    group: Option<&str>,
    app: Option<&str>,
    key: &str,
    env: Option<&str>,
) -> Result<()> {
    let owner = owner(group, app)?;
    let creds = config::resolve()?;
    let client = Client::from_creds(&creds)?;
    client.vars_delete(owner, key, env).await?;
    println!("Deleted var {key}");
    Ok(())
}
