//! Project scaffolding — creates the `.huskies/` directory structure and default files.

#![allow(unused_imports, dead_code)]
use std::fs;
use std::path::Path;

mod detect;
mod helpers;
mod templates;

use detect::{detect_components_toml, detect_script_build, detect_script_lint, detect_script_test};
use helpers::{
    append_root_gitignore_entries, generate_project_toml, write_file_if_missing,
    write_script_if_missing, write_story_kit_gitignore,
};
use templates::{
    BOT_TOML_MATRIX_EXAMPLE, BOT_TOML_SLACK_EXAMPLE, BOT_TOML_WHATSAPP_META_EXAMPLE,
    BOT_TOML_WHATSAPP_TWILIO_EXAMPLE, DEFAULT_AGENTS_TOML, STORY_KIT_CLAUDE_MD,
    STORY_KIT_CLAUDE_SETTINGS, STORY_KIT_CONTEXT, STORY_KIT_README, STORY_KIT_SCRIPT_TEST,
    STORY_KIT_STACK,
};

pub(crate) fn scaffold_story_kit(root: &Path, port: u16) -> Result<(), String> {
    let story_kit_root = root.join(".huskies");
    let specs_root = story_kit_root.join("specs");
    let tech_root = specs_root.join("tech");
    let functional_root = specs_root.join("functional");
    let script_root = root.join("script");

    // The `.huskies/work/` directory tree is no longer scaffolded — the CRDT
    // is the canonical pipeline state store (see stories 738 / 758 / 763).

    fs::create_dir_all(&tech_root).map_err(|e| format!("Failed to create specs/tech: {}", e))?;
    fs::create_dir_all(&functional_root)
        .map_err(|e| format!("Failed to create specs/functional: {}", e))?;
    fs::create_dir_all(&script_root)
        .map_err(|e| format!("Failed to create script/ directory: {}", e))?;

    write_file_if_missing(&story_kit_root.join("README.md"), STORY_KIT_README)?;
    let project_toml_content = generate_project_toml(root);
    write_file_if_missing(&story_kit_root.join("project.toml"), &project_toml_content)?;
    write_file_if_missing(&story_kit_root.join("agents.toml"), DEFAULT_AGENTS_TOML)?;
    write_file_if_missing(&specs_root.join("00_CONTEXT.md"), STORY_KIT_CONTEXT)?;
    write_file_if_missing(&tech_root.join("STACK.md"), STORY_KIT_STACK)?;
    let script_test_content = detect_script_test(root);
    write_script_if_missing(&script_root.join("test"), &script_test_content)?;
    let script_build_content = detect_script_build(root);
    write_script_if_missing(&script_root.join("build"), &script_build_content)?;
    let script_lint_content = detect_script_lint(root);
    write_script_if_missing(&script_root.join("lint"), &script_lint_content)?;
    write_file_if_missing(&root.join("CLAUDE.md"), STORY_KIT_CLAUDE_MD)?;

    // Write per-transport bot.toml example files so users can see all options.
    write_file_if_missing(
        &story_kit_root.join("bot.toml.matrix.example"),
        BOT_TOML_MATRIX_EXAMPLE,
    )?;
    write_file_if_missing(
        &story_kit_root.join("bot.toml.whatsapp-meta.example"),
        BOT_TOML_WHATSAPP_META_EXAMPLE,
    )?;
    write_file_if_missing(
        &story_kit_root.join("bot.toml.whatsapp-twilio.example"),
        BOT_TOML_WHATSAPP_TWILIO_EXAMPLE,
    )?;
    write_file_if_missing(
        &story_kit_root.join("bot.toml.slack.example"),
        BOT_TOML_SLACK_EXAMPLE,
    )?;

    // Write .mcp.json at the project root so agents can find the MCP server
    // via the HTTP MCP endpoint.
    // Only written when missing — never overwrites an existing file, because
    // the port is environment-specific and must not clobber a running instance.
    let mcp_content = format!(
        "{{\n  \"mcpServers\": {{\n    \"huskies\": {{\n      \"type\": \"http\",\n      \"url\": \"http://localhost:{port}/mcp\"\n    }}\n  }}\n}}\n"
    );
    write_file_if_missing(&root.join(".mcp.json"), &mcp_content)?;

    // Create .claude/settings.json with sensible permission defaults so that
    // Claude Code (both agents and web UI chat) can operate without constant
    // permission prompts.
    let claude_dir = root.join(".claude");
    fs::create_dir_all(&claude_dir)
        .map_err(|e| format!("Failed to create .claude/ directory: {}", e))?;
    write_file_if_missing(&claude_dir.join("settings.json"), STORY_KIT_CLAUDE_SETTINGS)?;

    write_story_kit_gitignore(root)?;
    append_root_gitignore_entries(root)?;

    // Run `git init` if the directory is not already a git repo, then make an initial commit
    if !root.join(".git").exists() {
        let init_status = std::process::Command::new("git")
            .args(["init"])
            .current_dir(root)
            .status()
            .map_err(|e| format!("Failed to run git init: {}", e))?;
        if !init_status.success() {
            return Err("git init failed".to_string());
        }

        let add_output = std::process::Command::new("git")
            .args([
                "add",
                ".huskies",
                "script",
                ".gitignore",
                "CLAUDE.md",
                ".claude",
            ])
            .current_dir(root)
            .output()
            .map_err(|e| format!("Failed to run git add: {}", e))?;
        if !add_output.status.success() {
            return Err(format!(
                "git add failed: {}",
                String::from_utf8_lossy(&add_output.stderr)
            ));
        }

        let commit_output = std::process::Command::new("git")
            .args([
                "-c",
                "user.email=huskies@localhost",
                "-c",
                "user.name=Story Kit",
                "commit",
                "-m",
                "Initial Story Kit scaffold",
            ])
            .current_dir(root)
            .output()
            .map_err(|e| format!("Failed to run git commit: {}", e))?;
        if !commit_output.status.success() {
            return Err(format!(
                "git commit failed: {}",
                String::from_utf8_lossy(&commit_output.stderr)
            ));
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests;
