//! Refactor-item creation and listing operations.

use std::path::Path;

use super::super::create_item_in_backlog;

/// Create a refactor work item and store it in the database.
///
/// Routes through `create_item_in_backlog`, the single internal creation path.
/// `acceptance_criteria` must be non-empty; an empty slice returns an error.
/// Returns the refactor_id (e.g. `"5"`).
pub fn create_refactor_file(
    root: &Path,
    name: &str,
    description: Option<&str>,
    acceptance_criteria: &[String],
    depends_on: Option<&[u32]>,
) -> Result<String, String> {
    let name_owned = name.to_string();
    let description_owned = description.map(str::to_string);
    let depends_on_owned: Option<Vec<u32>> = depends_on.map(<[u32]>::to_vec);
    let acs_owned: Vec<String> = acceptance_criteria.to_vec();

    create_item_in_backlog(
        root,
        "refactor",
        name,
        acceptance_criteria,
        depends_on,
        move |refactor_number| {
            let mut content = String::new();
            content.push_str("---\n");
            content.push_str("type: refactor\n");
            content.push_str(&format!("name: \"{}\"\n", name_owned.replace('"', "\\\"")));
            if let Some(ref deps) = depends_on_owned.filter(|d| !d.is_empty()) {
                let nums: Vec<String> = deps.iter().map(|n| n.to_string()).collect();
                content.push_str(&format!("depends_on: [{}]\n", nums.join(", ")));
            }
            content.push_str("---\n\n");
            content.push_str(&format!("# Refactor {refactor_number}: {name_owned}\n\n"));
            content.push_str("## Current State\n\n");
            content.push_str("- TBD\n\n");
            content.push_str("## Desired State\n\n");
            if let Some(ref desc) = description_owned {
                content.push_str(desc);
                content.push('\n');
            } else {
                content.push_str("- TBD\n");
            }
            content.push('\n');
            content.push_str("## Acceptance Criteria\n\n");
            for criterion in &acs_owned {
                content.push_str(&format!("- [ ] {criterion}\n"));
            }
            content.push('\n');
            content.push_str("## Out of Scope\n\n");
            content.push_str("- TBD\n");
            content
        },
    )
}

/// Returns true if the item stem is a refactor item.
///
/// Checks the slug-based ID format first (e.g. `"5_refactor_split_agents_rs"`),
/// then consults the typed CRDT `item_type` register for numeric-only IDs (933).
pub(super) fn is_refactor_item(stem: &str) -> bool {
    let after_num = stem.trim_start_matches(|c: char| c.is_ascii_digit());
    if after_num.starts_with("_refactor_") {
        return true;
    }
    if after_num.is_empty() {
        return crate::crdt_state::read_item(stem)
            .and_then(|v| v.item_type())
            .is_some_and(|t| t == crate::io::story_metadata::ItemType::Refactor);
    }
    false
}

/// List all open refactors from CRDT + content store.
///
/// Returns a sorted list of `(refactor_id, name)` pairs.
pub fn list_refactor_files(_root: &Path) -> Result<Vec<(String, String)>, String> {
    let mut refactors = Vec::new();

    for item in crate::pipeline_state::read_all_typed() {
        if !matches!(item.stage, crate::pipeline_state::Stage::Backlog)
            || !is_refactor_item(&item.story_id.0)
        {
            continue;
        }
        let sid = item.story_id.0;
        let name = if item.name.is_empty() {
            sid.clone()
        } else {
            item.name
        };
        refactors.push((sid, name));
    }

    refactors.sort_by(|a, b| a.0.cmp(&b.0));
    Ok(refactors)
}
