//! `sprouts init` — scaffold a new sprout crate.

use std::path::PathBuf;

use anyhow::{bail, Context};
use clap::Args as ClapArgs;

#[derive(ClapArgs)]
pub struct Args {
    /// The sprout name (also the directory + crate name).
    name: String,
}

pub fn run(args: Args) -> anyhow::Result<()> {
    let name = args.name;
    let dir = PathBuf::from(&name);
    if dir.exists() {
        bail!("`{name}` already exists");
    }
    let crate_name = name.replace('-', "_");

    std::fs::create_dir_all(dir.join("src")).context("creating sprout directory")?;
    std::fs::write(dir.join("Cargo.toml"), cargo_toml(&name)).context("writing Cargo.toml")?;
    std::fs::write(dir.join("sprout.toml"), sprout_toml(&name)).context("writing sprout.toml")?;
    std::fs::write(dir.join("src/lib.rs"), lib_rs(&crate_name)).context("writing src/lib.rs")?;

    println!("Created sprout `{name}`.");
    println!("  cd {name}");
    println!("  sprouts deploy");
    Ok(())
}

fn cargo_toml(name: &str) -> String {
    format!(
        r#"# A sprout is its own standalone crate (the empty [workspace] keeps it
# independent even when created inside another cargo workspace).
[workspace]

[package]
name = "{name}"
version = "0.1.0"
edition = "2024"

# A sprout compiles to a WebAssembly module that the engine runs.
[lib]
crate-type = ["cdylib"]

[dependencies]
cotyledon = "0.1"
serde = {{ version = "1", features = ["derive"] }}
"#
    )
}

fn sprout_toml(name: &str) -> String {
    format!(
        r#"name = "{name}"
wallet = false

# A scheduled trigger. `handler` names a function in the program module below.
[triggers.tick]
on = "schedule"
cron = "*/5 * * * *"
handler = "tick"

[config]
token = "SOL"
"#
    )
}

fn lib_rs(_crate_name: &str) -> String {
    r#"//! A starter sprout. Handlers are free functions in the `#[sprout::program]`
//! module; each trigger in `sprout.toml` names the handler it invokes.

use cotyledon::prelude::*;
use serde::Deserialize;

#[derive(Deserialize)]
pub struct Config {
    token: String,
}

#[sprout::program]
pub mod starter {
    use super::*;

    /// Bound to `[triggers.tick]`. Logs the token's current price.
    pub async fn tick(ctx: Ctx) -> Result<()> {
        let cfg = ctx.config::<Config>()?;
        let price = ctx.price(&cfg.token).await?;
        ctx.log().info(&format!("{} is ${price}", cfg.token));
        Ok(())
    }
}
"#
    .to_string()
}
