adrs 0.7.6

Command line tool for managing Architecture Decision Records
//! New ADR command.

use adrs_core::{
    AdrStatus, Config, ConfigMode, LinkKind, Repository, Template, TemplateFormat, TemplateVariant,
};
use anyhow::{Context, Result};
use std::path::{Path, PathBuf};

#[allow(clippy::too_many_arguments)]
pub fn new(
    root: &Path,
    ng: bool,
    title: String,
    supersedes: Option<u32>,
    link: Option<String>,
    format: Option<String>,
    variant: Option<String>,
    template: Option<PathBuf>,
    status: Option<String>,
    tags: Option<Vec<String>>,
    no_edit: bool,
    config: &Config,
) -> Result<()> {
    // Parse template format: CLI arg > config > default
    let template_format = if let Some(ref fmt) = format {
        fmt.parse::<TemplateFormat>()
            .context("Invalid template format. Use 'nygard' or 'madr'.")?
    } else if let Some(ref fmt) = config.templates.format {
        fmt.parse::<TemplateFormat>()
            .context("Invalid template format in config. Use 'nygard' or 'madr'.")?
    } else {
        TemplateFormat::default()
    };

    // Parse template variant: CLI arg > config > default
    let template_variant = if let Some(ref var) = variant {
        var.parse::<TemplateVariant>()
            .context("Invalid template variant. Use 'full', 'minimal', or 'bare'.")?
    } else if let Some(ref var) = config.templates.variant {
        var.parse::<TemplateVariant>()
            .context("Invalid template variant in config. Use 'full', 'minimal', or 'bare'.")?
    } else {
        TemplateVariant::default()
    };

    // Parse status if specified
    let initial_status = if let Some(ref s) = status {
        s.parse::<AdrStatus>().unwrap_or(AdrStatus::Proposed)
    } else {
        AdrStatus::Proposed
    };

    let mut repo = Repository::open(root)
        .context("ADR repository not found. Run 'adrs init' first.")?
        .with_template_format(template_format)
        .with_template_variant(template_variant);

    // Override mode if --ng flag is passed
    if ng {
        repo = repo.with_mode(ConfigMode::NextGen);
    }

    // Apply custom template: CLI --template > config custom > built-in format/variant
    if let Some(ref cli_path) = template {
        // CLI flag takes highest precedence
        let tmpl = Template::from_file(cli_path).context(format!(
            "Failed to load custom template from {}: check the path is correct",
            cli_path.display()
        ))?;
        repo = repo.with_custom_template(tmpl);
    } else if format.is_none()
        && variant.is_none()
        && let Some(ref custom_path) = config.templates.custom
    {
        // Config custom path applies when no CLI format/variant override is given
        let full_path = root.join(custom_path);
        let tmpl = Template::from_file(&full_path).context(format!(
            "Failed to load custom template from config: {}",
            custom_path.display()
        ))?;
        repo = repo.with_custom_template(tmpl);
    }

    let (mut adr, path) = if let Some(superseded) = supersedes {
        repo.supersede(&title, superseded)
            .context("Failed to create superseding ADR")?
    } else {
        repo.new_adr(&title).context("Failed to create new ADR")?
    };

    // Set custom status if specified (and not superseding, which sets its own status)
    if supersedes.is_none() && status.is_some() {
        adr.status = initial_status;
        repo.update_metadata(&adr)
            .context("Failed to update ADR status")?;
    }

    // Effective ng mode: CLI flag --ng OR config mode = "ng"
    let is_ng = ng || config.is_next_gen();

    // Set tags if specified (requires ng mode for YAML frontmatter)
    if let Some(tag_list) = tags {
        if !is_ng {
            anyhow::bail!(
                "Tags require --ng mode (YAML frontmatter). Use: adrs --ng new --tags ... or set mode = \"ng\" in adrs.toml"
            );
        }
        if !tag_list.is_empty() {
            adr.set_tags(tag_list);
            repo.update_metadata(&adr)
                .context("Failed to update ADR tags")?;
        }
    }

    // Handle linking if specified
    if let Some(link_spec) = link {
        let parts: Vec<&str> = link_spec.split(':').collect();
        if parts.len() == 3 {
            let target: u32 = parts[0]
                .parse()
                .context("Invalid target ADR number in link")?;
            let kind: LinkKind = parts[1].parse().unwrap_or(LinkKind::RelatesTo);
            let reverse_kind: LinkKind = parts[2].parse().unwrap_or(LinkKind::RelatesTo);

            repo.link(adr.number, target, kind, reverse_kind)
                .context("Failed to create link")?;
        }
    }

    // Open in editor unless --no-edit was specified
    if !no_edit {
        edit::edit_file(&path).context("Failed to open editor")?;
    }

    println!("{}", path.display());
    Ok(())
}