use std::path::Path;

use super::*;

// ─────────────────────────────────────────────────────
// cfgd init — pure scaffolding
// ─────────────────────────────────────────────────────

pub(super) struct InitArgs<'a> {
    pub path: Option<&'a str>,
    pub from: Option<&'a str>,
    pub branch: &'a str,
    pub name: Option<&'a str>,
    pub apply: bool,
    pub dry_run: bool,
    pub yes: bool,
    pub install_daemon: bool,
    pub theme: Option<&'a str>,
    pub apply_profile: Option<&'a str>,
    pub apply_modules: &'a [String],
}

/// Scaffold a new cfgd configuration repository.
pub(super) fn cmd_init(printer: &Printer, args: &InitArgs<'_>) -> anyhow::Result<()> {
    printer.header("Initialize cfgd");

    if !check_prerequisites(printer) {
        return Ok(());
    }

    // 1. Determine target directory and whether --from did a fresh clone
    let from_used = args.from.is_some();
    let target_dir = if let Some(from) = args.from {
        let explicit_path = args.path.map(|p| cfgd_core::expand_tilde(Path::new(p)));
        resolve_from(from, explicit_path.as_deref(), args.branch, printer)?
    } else {
        match args.path {
            Some(p) => cfgd_core::expand_tilde(Path::new(p)),
            None => std::env::current_dir()?,
        }
    };

    // 2. Create directory if it doesn't exist
    if !target_dir.exists() {
        std::fs::create_dir_all(&target_dir)?;
    }

    // 3. Check if already initialized
    // When --from is used, resolve_from handles the "already initialized" case
    // and the clone creates cfgd.yaml — skip this check so we reach the apply step
    if target_dir.join("cfgd.yaml").exists() && !from_used {
        printer.info(&format!("Already initialized at {}", target_dir.display()));
        return Ok(());
    }

    // 4. Clone or scaffold
    // When --from is a git source, resolve_from already cloned it above.
    // Only clone here if resolve_from didn't handle it (non-git --from or no --from).
    if let Some(url) = args.from.filter(|f| is_git_source(f)) {
        if !target_dir.join(".git").exists() {
            clone_into(&target_dir, url, args.branch, printer)?;
        }
        // If --theme was specified and the cloned repo has a cfgd.yaml, set the theme
        if let Some(theme) = args.theme {
            let config_path = target_dir.join("cfgd.yaml");
            if config_path.exists() {
                let mut cfg = config::load_config(&config_path)?;
                cfg.spec.theme = Some(config::ThemeConfig {
                    name: theme.to_string(),
                    overrides: config::ThemeOverrides::default(),
                });
                let yaml = serde_yaml::to_string(&cfg)?;
                cfgd_core::atomic_write_str(&config_path, &yaml)?;
            }
        }
    } else {
        scaffold(&target_dir, args.name, args.theme, printer)?;
    }

    // 5. Generate release workflow — only for scaffolded repos, not cloned ones.
    // Cloned repos already have their own workflows; writing into them dirties the tree.
    if !from_used {
        regenerate_workflow(&target_dir, printer)?;
    }

    // 6. Git init if not already a repo
    if !target_dir.join(".git").exists() {
        match git2::Repository::init(&target_dir) {
            Ok(_) => printer.success("Initialized git repository"),
            Err(e) => printer.warning(&format!("Failed to init git repo: {}", e)),
        }
    }

    printer.newline();
    printer.success(&format!("Initialized at {}", target_dir.display()));

    // 7. Apply if requested
    let should_apply = args.apply || args.apply_profile.is_some() || !args.apply_modules.is_empty();
    if should_apply {
        let config_path = target_dir.join("cfgd.yaml");
        let profiles_dir = target_dir.join("profiles");

        // Module-only apply: no profile needed
        let module_only = !args.apply_modules.is_empty() && args.apply_profile.is_none();

        if module_only {
            // Validate that requested modules exist
            let cache_base = modules::default_module_cache_dir()?;
            let all_modules = modules::load_all_modules(&target_dir, &cache_base, printer)?;
            for m in args.apply_modules {
                let resolved_name = modules::resolve_profile_module_name(m);
                if !all_modules.contains_key(resolved_name) {
                    anyhow::bail!("Module '{}' not found in {}", m, target_dir.display());
                }
            }

            printer.newline();
            printer.header("Applying Modules");

            let cfg = config::load_config(&config_path)?;
            let registry = super::build_registry_with_config(Some(&cfg));
            let store = super::open_state_store(None)?;

            // Build a minimal resolved profile for the reconciler
            let resolved = config::ResolvedProfile {
                layers: Vec::new(),
                merged: config::MergedProfile::default(),
            };

            let platform = cfgd_core::platform::Platform::detect();
            let mgr_map = super::managers_map(&registry);
            let resolved_modules = modules::resolve_modules(
                args.apply_modules,
                &target_dir,
                &cache_base,
                &platform,
                &mgr_map,
                printer,
            )?;

            let reconciler = cfgd_core::reconciler::Reconciler::new(&registry, &store);
            let plan = reconciler.plan(
                &resolved,
                Vec::new(),
                Vec::new(),
                resolved_modules,
                cfgd_core::reconciler::ReconcileContext::Apply,
            )?;

            apply_plan(
                &plan,
                &reconciler,
                &resolved,
                &target_dir,
                args.dry_run,
                args.yes,
                printer,
            )?;
        } else {
            // Profile-based apply
            let profile_name = if let Some(name) = args.apply_profile {
                // Validate profile exists
                let profile_path = profiles_dir.join(format!("{}.yaml", name));
                if !profile_path.exists() {
                    anyhow::bail!("Profile '{}' not found at {}", name, profile_path.display());
                }
                // Set as active profile in cfgd.yaml
                let mut cfg = config::load_config(&config_path)?;
                cfg.spec.profile = Some(name.to_string());
                let yaml = serde_yaml::to_string(&cfg)?;
                cfgd_core::atomic_write_str(&config_path, &yaml)?;
                printer.success(&format!("Set active profile: {}", name));
                name.to_string()
            } else {
                // No --apply-profile: use whatever's in cfgd.yaml, or pick interactively
                let cfg = config::load_config(&config_path)?;
                if let Some(ref p) = cfg.spec.profile {
                    p.clone()
                } else {
                    pick_profile(&profiles_dir, printer)?
                }
            };

            printer.newline();
            printer.header("Applying Configuration");

            let cfg = config::load_config(&config_path)?;
            let resolved = config::resolve_profile(&profile_name, &profiles_dir)?;
            let mut registry = super::build_registry_with_config(Some(&cfg));
            let store = super::open_state_store(None)?;

            // Resolve modules (profile modules + any --apply-module additions)
            let mut module_names = resolved.merged.modules.clone();
            for m in args.apply_modules {
                if !module_names.contains(m) {
                    module_names.push(m.clone());
                }
            }

            let resolved_modules = if !module_names.is_empty() {
                let platform = cfgd_core::platform::Platform::detect();
                let mgr_map = super::managers_map(&registry);
                let cache_base = modules::default_module_cache_dir()?;
                // Validate --apply-module names exist (load once, check all)
                let all_modules = modules::load_all_modules(&target_dir, &cache_base, printer)?;
                for m in args.apply_modules {
                    let resolved_name = modules::resolve_profile_module_name(m);
                    if !all_modules.contains_key(resolved_name) {
                        anyhow::bail!("Module '{}' not found in {}", m, target_dir.display());
                    }
                }
                modules::resolve_modules(
                    &module_names,
                    &target_dir,
                    &cache_base,
                    &platform,
                    &mgr_map,
                    printer,
                )?
            } else {
                Vec::new()
            };

            let all_managers: Vec<&dyn cfgd_core::providers::PackageManager> = registry
                .package_managers
                .iter()
                .map(|m| m.as_ref())
                .collect();
            let pkg_actions = super::packages::plan_packages(&resolved.merged, &all_managers)?;

            let fm = super::CfgdFileManager::new(&target_dir, &resolved)?;
            let file_actions = fm.plan(&resolved.merged)?;

            registry.file_manager = Some(Box::new(fm));

            let reconciler = cfgd_core::reconciler::Reconciler::new(&registry, &store);
            let plan = reconciler.plan(
                &resolved,
                file_actions,
                pkg_actions,
                resolved_modules,
                cfgd_core::reconciler::ReconcileContext::Apply,
            )?;

            apply_plan(
                &plan,
                &reconciler,
                &resolved,
                &target_dir,
                args.dry_run,
                args.yes,
                printer,
            )?;
        }
    }

    // 8. Install daemon if requested
    if args.install_daemon {
        #[cfg(any(unix, windows))]
        {
            let config_path = target_dir.join("cfgd.yaml");
            let cfg = config::load_config(&config_path)?;
            let profile = cfg.spec.profile.as_deref();
            match cfgd_core::daemon::install_service(&config_path, profile) {
                Ok(()) => {
                    printer.success("Daemon service installed");
                    #[cfg(windows)]
                    printer.info("The service will start automatically on boot");
                }
                Err(e) => {
                    printer.warning(&format!("Failed to install daemon: {}", e));
                    printer.info("Install later with: cfgd daemon install");
                }
            }
        }
        #[cfg(not(any(unix, windows)))]
        {
            printer.warning("Daemon service installation is not supported on this platform");
            printer.info("Run the daemon directly with: cfgd daemon");
        }
    }

    // 9. Print next steps
    if !args.apply {
        printer.newline();
        printer.info("Next steps:");
        printer.info("  cfgd module create <name>   — create a module");
        printer.info("  cfgd profile create <name>  — create a profile");
        printer.info("  cfgd apply                  — apply configuration");
    }

    Ok(())
}

/// Show plan, prompt for confirmation, and apply.
fn apply_plan(
    plan: &cfgd_core::reconciler::Plan,
    reconciler: &cfgd_core::reconciler::Reconciler<'_>,
    resolved: &config::ResolvedProfile,
    config_dir: &Path,
    dry_run: bool,
    yes: bool,
    printer: &Printer,
) -> anyhow::Result<()> {
    let total = plan.total_actions();
    if total == 0 {
        printer.success("Nothing to do — system is already configured");
        return Ok(());
    }

    super::display_plan_table(plan, printer, None);
    printer.info(&format!("{} action(s) planned", total));

    if dry_run {
        return Ok(());
    }

    if !yes {
        let confirmed = printer
            .prompt_confirm("Apply these changes?")
            .unwrap_or(false);
        if !confirmed {
            printer.info("Skipped — run 'cfgd apply' to apply later");
            return Ok(());
        }
    }

    let state_dir = cfgd_core::state::default_state_dir()
        .map_err(|e| anyhow::anyhow!("cannot determine state directory: {}", e))?;
    let _apply_lock = cfgd_core::acquire_apply_lock(&state_dir)?;

    let result = reconciler.apply(
        plan,
        resolved,
        config_dir,
        printer,
        None,
        &[],
        cfgd_core::reconciler::ReconcileContext::Apply,
        false,
    )?;
    super::print_apply_result(&result, printer);
    Ok(())
}

/// Interactively pick a profile from the profiles directory.
fn pick_profile(profiles_dir: &Path, printer: &Printer) -> anyhow::Result<String> {
    if !profiles_dir.is_dir() {
        anyhow::bail!(
            "No profiles directory found — create a profile first with: cfgd profile create <name>"
        );
    }

    let names = super::list_yaml_stems(profiles_dir)?;

    if names.is_empty() {
        anyhow::bail!(
            "No profiles found — create a profile first with: cfgd profile create <name>"
        );
    }

    if names.len() == 1 {
        printer.info(&format!("Using only available profile: {}", names[0]));
        return Ok(names[0].clone());
    }

    printer.subheader("Available Profiles");
    for (i, name) in names.iter().enumerate() {
        printer.info(&format!("  {}. {}", i + 1, name));
    }

    let input = printer.prompt_text(&format!("Select profile (1-{}) or name", names.len()), "1")?;

    // Try as number first
    if let Ok(n) = input.parse::<usize>()
        && n >= 1
        && n <= names.len()
    {
        return Ok(names[n - 1].clone());
    }

    // Try as name
    if names.contains(&input) {
        return Ok(input);
    }

    anyhow::bail!(
        "Invalid selection '{}' — expected a number or profile name",
        input
    )
}

/// Returns true if the value is a clonable git source (URL or local git repo).
pub(super) fn is_git_source(value: &str) -> bool {
    // Remote URLs
    if value.starts_with("https://")
        || value.starts_with("http://")
        || value.starts_with("ssh://")
        || value.starts_with("git://")
        || value.starts_with("git@")
        || value.ends_with(".git")
    {
        return true;
    }
    // Local git repos
    let path = cfgd_core::expand_tilde(Path::new(value));
    path.join(".git").exists()
}

/// Resolve a --from value to a config directory path.
/// Git sources (URLs or local repos) are cloned to the target dir.
/// Plain local paths are used directly (must contain cfgd.yaml).
pub(super) fn resolve_from(
    from: &str,
    target: Option<&Path>,
    branch: &str,
    printer: &cfgd_core::output::Printer,
) -> anyhow::Result<std::path::PathBuf> {
    if is_git_source(from) {
        let dest = target
            .map(|p| p.to_path_buf())
            .unwrap_or_else(cfgd_core::default_config_dir);
        if !dest.join("cfgd.yaml").exists() {
            std::fs::create_dir_all(&dest)?;
            clone_into(&dest, from, branch, printer)?;
        } else {
            printer.info(&format!("Already initialized at {}", dest.display()));
        }
        Ok(dest)
    } else {
        let path = cfgd_core::expand_tilde(Path::new(from));
        if !path.exists() {
            anyhow::bail!("Path does not exist: {}", path.display());
        }
        if !path.join("cfgd.yaml").exists() {
            anyhow::bail!("No cfgd.yaml found in {}", path.display());
        }
        Ok(path)
    }
}

/// Clone a remote repo into the target directory.
fn clone_into(target_dir: &Path, url: &str, branch: &str, printer: &Printer) -> anyhow::Result<()> {
    // If target already has .git, it's already cloned — nothing to do.
    if target_dir.join(".git").exists() {
        printer.info("Repository already exists, skipping clone");
        return Ok(());
    }

    cfgd_core::sources::git_clone_with_fallback(url, target_dir, printer)
        .map_err(|e| anyhow::anyhow!("Clone failed: {}", e))?;

    printer.success(&format!("Cloned to {}", target_dir.display()));

    // Checkout the requested branch if HEAD isn't already on it.
    // git clone checks out the remote's default branch; if the user asked for
    // a different one we need to switch.
    let repo = git2::Repository::open(target_dir)
        .map_err(|e| anyhow::anyhow!("Failed to open cloned repo: {}", e))?;
    let current_branch = repo
        .head()
        .ok()
        .and_then(|h| h.shorthand().map(String::from))
        .unwrap_or_default();
    if current_branch != branch {
        let remote_branch = format!("origin/{}", branch);
        let obj = repo
            .revparse_single(&remote_branch)
            .map_err(|_| anyhow::anyhow!("Branch '{}' not found in remote", branch))?;
        repo.checkout_tree(&obj, None)
            .map_err(|e| anyhow::anyhow!("Failed to checkout '{}': {}", branch, e))?;
        repo.set_head(&format!("refs/heads/{}", branch))
            .map_err(|e| anyhow::anyhow!("Failed to set HEAD to '{}': {}", branch, e))?;
        printer.info(&format!("Checked out branch: {}", branch));
    }

    Ok(())
}

/// Create the cfgd directory structure from scratch.
fn scaffold(
    dir: &Path,
    name: Option<&str>,
    theme: Option<&str>,
    printer: &Printer,
) -> anyhow::Result<()> {
    let config_name = name
        .or_else(|| dir.file_name().and_then(|n| n.to_str()))
        .unwrap_or("my-config");

    // Create directories
    std::fs::create_dir_all(dir.join("profiles"))?;
    std::fs::create_dir_all(dir.join("modules"))?;
    printer.success("Created profiles/ modules/");

    // cfgd.yaml
    let theme_value = theme.unwrap_or("default");
    let content = format!(
        r#"apiVersion: cfgd.io/v1alpha1
kind: Config
metadata:
  name: {config_name}
spec:
  theme: {theme_value}
  fileStrategy: Symlink
  aliases:
    add: "profile update --file"
    remove: "profile update --file"
  # profile: base
  # modules:
  #   registries: []
  # sources: []
"#
    );
    cfgd_core::atomic_write_str(&dir.join("cfgd.yaml"), &content)?;
    printer.success("Created cfgd.yaml");

    // .gitignore — ignore everything except cfgd-managed content
    let gitignore = "\
# Ignore everything by default
**

# cfgd config
!cfgd.yaml
!.gitignore
!README.md

# Profiles and modules
!profiles/
!profiles/**
!modules/
!modules/**

# CI
!.github/
!.github/**
";
    cfgd_core::atomic_write_str(&dir.join(".gitignore"), gitignore)?;
    printer.success("Created .gitignore");

    // README.md
    let readme = format!(
        r#"# {config_name}

Machine configuration managed by [cfgd](https://github.com/tj-smith47/cfgd).

## Quick start

```bash
cfgd init --from <this-repo-url>
cfgd apply
```

## Structure

- `profiles/` — machine profiles (which modules, packages, env, system settings to apply)
- `modules/` — self-contained configuration units (packages, files, env, scripts)
- `cfgd.yaml` — config root (active profile, sources, theme)
"#
    );
    cfgd_core::atomic_write_str(&dir.join("README.md"), &readme)?;
    printer.success("Created README.md");

    // Workflow — generate a base workflow even with no modules/profiles yet.
    // It gets regenerated when modules/profiles are added.
    let workflow_dir = dir.join(".github").join("workflows");
    std::fs::create_dir_all(&workflow_dir)?;
    let workflow = generate_release_workflow_yaml(&[], &[]);
    cfgd_core::atomic_write_str(&workflow_dir.join("cfgd-release.yml"), &workflow)?;
    printer.success("Created .github/workflows/cfgd-release.yml");

    Ok(())
}

/// Generate or regenerate the release workflow based on current modules/profiles.
/// Called by init and also by module create / profile create.
pub(super) fn regenerate_workflow(config_dir: &Path, printer: &Printer) -> anyhow::Result<()> {
    let profiles = scan_profile_names(&config_dir.join("profiles"))?;
    let modules = scan_module_names(&config_dir.join("modules"))?;

    if profiles.is_empty() && modules.is_empty() {
        return Ok(());
    }

    let workflow_dir = config_dir.join(".github").join("workflows");
    std::fs::create_dir_all(&workflow_dir)?;

    let yaml = generate_release_workflow_yaml(&modules, &profiles);
    cfgd_core::atomic_write_str(&workflow_dir.join("cfgd-release.yml"), &yaml)?;
    printer.success("Generated .github/workflows/cfgd-release.yml");

    Ok(())
}

fn check_prerequisites(printer: &Printer) -> bool {
    if !cfgd_core::command_available("git") {
        printer.error("git is not installed — cfgd requires git");
        if cfg!(target_os = "macos") {
            printer.info("Install with: xcode-select --install");
        } else {
            printer.info("Install with: sudo apt install git (or your package manager)");
        }
        return false;
    }
    true
}

// ─────────────────────────────────────────────────────
// ensure_config_file — used by profile switch and tests
// ─────────────────────────────────────────────────────

#[cfg(test)]
fn ensure_config_file(
    config_dir: &Path,
    config_path: &Path,
    profile_name: &str,
    from_url: Option<&str>,
    branch: &str,
    theme: Option<&str>,
) -> anyhow::Result<()> {
    if config_path.exists() {
        let contents = std::fs::read_to_string(config_path)?;
        let mut cfg = config::parse_config(&contents, config_path)?;
        if cfg.spec.profile.as_deref() != Some(profile_name) {
            cfg.spec.profile = Some(profile_name.to_string());
            let yaml = serde_yaml::to_string(&cfg)?;
            cfgd_core::atomic_write_str(config_path, &yaml)?;
        }
        return Ok(());
    }

    let name = config_dir
        .file_name()
        .and_then(|n| n.to_str())
        .unwrap_or("my-config");

    let origin_section = if let Some(url) = from_url {
        format!(
            r#"  origin:
    type: Git
    url: {}
    branch: {}
"#,
            url, branch
        )
    } else {
        String::new()
    };

    let theme_value = theme.unwrap_or("default");

    let config_content = format!(
        r#"apiVersion: cfgd.io/v1alpha1
kind: Config
metadata:
  name: {}
spec:
  profile: {}
  theme: {}
  fileStrategy: Symlink
{}"#,
        name, profile_name, theme_value, origin_section
    );

    cfgd_core::atomic_write_str(config_path, &config_content)?;
    Ok(())
}

// ─────────────────────────────────────────────────────
// count_packages — used by profile display
// ─────────────────────────────────────────────────────

#[cfg(test)]
fn count_packages(spec: &config::ProfileSpec) -> usize {
    let mut count = 0;
    if let Some(ref pkgs) = spec.packages {
        if let Some(ref brew) = pkgs.brew {
            count += brew.formulae.len() + brew.casks.len();
        }
        if let Some(ref apt) = pkgs.apt {
            count += apt.packages.len();
        }
        if let Some(ref cargo) = pkgs.cargo {
            count += cargo.packages.len();
        }
        if let Some(ref npm) = pkgs.npm {
            count += npm.global.len();
        }
        count += pkgs.pipx.len();
        count += pkgs.dnf.len();
    }
    count
}

// ─────────────────────────────────────────────────────
// cfgd enroll — unified enrollment (token + key-based)
// ─────────────────────────────────────────────────────

pub(super) fn cmd_enroll(
    printer: &Printer,
    server_url: &str,
    token: Option<&str>,
    ssh_key: Option<&str>,
    gpg_key: Option<&str>,
    username: Option<&str>,
) -> anyhow::Result<()> {
    let username = match username {
        Some(u) => u.to_string(),
        None => std::env::var("USER").unwrap_or_else(|_| "unknown".to_string()),
    };
    let device_id = default_device_id();

    printer.key_value("Server", server_url);
    printer.key_value("Device ID", &device_id);

    let client = cfgd_core::server_client::ServerClient::new(server_url, None, &device_id);

    // Token-based enrollment (direct exchange)
    if let Some(token) = token {
        printer.header("Token Enrollment");
        printer.info("Exchanging bootstrap token for device credential...");

        let resp = client
            .enroll(token, printer)
            .map_err(|e| anyhow::anyhow!("{}", e))?;

        return finish_enrollment(printer, server_url, &device_id, resp);
    }

    // Key-based enrollment (challenge-response)
    printer.header("Key-Based Enrollment");
    printer.key_value("Username", &username);

    // Check server enrollment method
    let info = client.enroll_info().map_err(|e| anyhow::anyhow!("{}", e))?;

    if info.method == "token" {
        anyhow::bail!(
            "This server uses bootstrap token enrollment. Run: cfgd enroll --server-url <url> --token <token>"
        );
    }

    // Determine signing method
    let (key_type, key_ref) = if let Some(gpg_id) = gpg_key {
        ("gpg".to_string(), gpg_id.to_string())
    } else if let Some(ssh_path) = ssh_key {
        ("ssh".to_string(), ssh_path.to_string())
    } else {
        match detect_ssh_key(printer) {
            Some(path) => ("ssh".to_string(), path),
            None => {
                anyhow::bail!(
                    "no SSH key found — provide --ssh-key <path> or --gpg-key <id>\n\
                     Checked: SSH agent, ~/.ssh/id_ed25519, ~/.ssh/id_rsa, ~/.ssh/id_ecdsa"
                );
            }
        }
    };

    printer.key_value(
        "Signing with",
        &format!("{} ({})", key_type.to_uppercase(), key_ref),
    );
    printer.newline();

    // Challenge-response
    let challenge = client
        .request_challenge(&username, printer)
        .map_err(|e| anyhow::anyhow!("{}", e))?;

    printer.key_value("Challenge ID", &challenge.challenge_id);
    printer.key_value("Expires", &challenge.expires_at);

    let signature = match key_type.as_str() {
        "ssh" => sign_with_ssh(&challenge.nonce, &key_ref)?,
        "gpg" => sign_with_gpg(&challenge.nonce, &key_ref)?,
        _ => unreachable!(),
    };

    printer.success("Challenge signed");

    let resp = client
        .submit_verification(&challenge.challenge_id, &signature, &key_type, printer)
        .map_err(|e| anyhow::anyhow!("{}", e))?;

    finish_enrollment(printer, server_url, &device_id, resp)
}

/// Shared enrollment completion: save credential, handle desired config, print next steps.
fn finish_enrollment(
    printer: &Printer,
    server_url: &str,
    device_id: &str,
    resp: cfgd_core::server_client::EnrollResponse,
) -> anyhow::Result<()> {
    printer.newline();
    printer.success(&format!("Enrolled as user '{}'", resp.username));
    if let Some(ref team) = resp.team {
        printer.key_value("Team", team);
    }
    printer.key_value("Device", &resp.device_id);

    let credential = cfgd_core::server_client::DeviceCredential {
        server_url: server_url.to_string(),
        device_id: device_id.to_string(),
        api_key: resp.api_key.clone(),
        username: resp.username.clone(),
        team: resp.team.clone(),
        enrolled_at: cfgd_core::utc_now_iso8601(),
    };

    match cfgd_core::server_client::save_credential(&credential) {
        Ok(path) => {
            printer.success(&format!("Credential saved to {}", path.display()));
        }
        Err(e) => {
            printer.error(&format!("Failed to save credential: {}", e));
            printer.warning("You will need to manually provide --api-key for future commands");
        }
    }

    if let Some(ref desired) = resp.desired_config {
        match cfgd_core::state::save_pending_server_config(desired) {
            Ok(path) => {
                printer.newline();
                printer.info(&format!(
                    "Server pushed desired config — saved to {}",
                    path.display()
                ));
                printer.info(MSG_RUN_APPLY);
            }
            Err(e) => {
                tracing::warn!(error = %e, "Failed to save pending server config");
            }
        }
    }

    printer.newline();
    printer.header("Next Steps");
    printer.info("  cfgd checkin --server-url <url>  — report status to server");
    printer.info("  cfgd apply --dry-run             — preview configuration");
    printer.info("  cfgd apply                       — apply configuration");
    printer.info("  cfgd daemon install               — start background sync");

    Ok(())
}

// ─────────────────────────────────────────────────────
// SSH/GPG signing helpers
// ─────────────────────────────────────────────────────

fn detect_ssh_key(printer: &Printer) -> Option<String> {
    // Try SSH agent first
    if cfgd_core::command_available("ssh-add")
        && let Ok(output) = cfgd_core::command_output_with_timeout(
            std::process::Command::new("ssh-add").arg("-l"),
            std::time::Duration::from_secs(5),
        )
        && output.status.success()
    {
        let stdout = String::from_utf8_lossy(&output.stdout);
        if let Some(line) = stdout.lines().next()
            && !line.contains("no identities")
        {
            let ssh_dir = cfgd_core::expand_tilde(Path::new("~/.ssh"));
            for key_name in &["id_ed25519", "id_rsa", "id_ecdsa"] {
                let pub_path = ssh_dir.join(format!("{key_name}.pub"));
                if pub_path.exists() {
                    printer.info(&format!("Using SSH key from agent: {}", pub_path.display()));
                    return Some(pub_path.to_string_lossy().to_string());
                }
            }
            for key_name in &["id_ed25519", "id_rsa", "id_ecdsa"] {
                let key_path = ssh_dir.join(key_name);
                if key_path.exists() {
                    printer.info(&format!("Using SSH key: {}", key_path.display()));
                    return Some(key_path.to_string_lossy().to_string());
                }
            }
        }
    }

    // Fall back to on-disk keys
    let ssh_dir = cfgd_core::expand_tilde(Path::new("~/.ssh"));
    for key_name in &["id_ed25519", "id_rsa", "id_ecdsa"] {
        let pub_path = ssh_dir.join(format!("{key_name}.pub"));
        if pub_path.exists() {
            printer.info(&format!("Using SSH key: {}", pub_path.display()));
            return Some(pub_path.to_string_lossy().to_string());
        }
        let key_path = ssh_dir.join(key_name);
        if key_path.exists() {
            printer.info(&format!("Using SSH key: {}", key_path.display()));
            return Some(key_path.to_string_lossy().to_string());
        }
    }

    None
}

fn sign_with_ssh(nonce: &str, key_path: &str) -> anyhow::Result<String> {
    if !cfgd_core::command_available("ssh-keygen") {
        anyhow::bail!("ssh-keygen not found — is OpenSSH installed?");
    }

    let tmp_dir = tempfile::tempdir()?;
    let data_path = tmp_dir.path().join("challenge.txt");
    let sig_path = tmp_dir.path().join("challenge.txt.sig");

    std::fs::write(&data_path, nonce)?;

    let status = std::process::Command::new("ssh-keygen")
        .args([
            "-Y",
            "sign",
            "-f",
            key_path,
            "-n",
            "cfgd-enroll",
            data_path.to_str().unwrap_or("challenge.txt"),
        ])
        .stdout(std::process::Stdio::null())
        .stderr(std::process::Stdio::piped())
        .status()
        .map_err(|e| anyhow::anyhow!("ssh-keygen not found: {e} — is OpenSSH installed?"))?;

    if !status.success() {
        anyhow::bail!("ssh-keygen -Y sign failed — check that your SSH key is accessible");
    }

    let signature = std::fs::read_to_string(&sig_path)
        .map_err(|e| anyhow::anyhow!("failed to read SSH signature: {e}"))?;

    Ok(signature)
}

fn sign_with_gpg(nonce: &str, gpg_key_id: &str) -> anyhow::Result<String> {
    if !cfgd_core::command_available("gpg") {
        anyhow::bail!("gpg not found — is GnuPG installed?");
    }

    let tmp_dir = tempfile::tempdir()?;
    let data_path = tmp_dir.path().join("challenge.txt");
    let sig_path = tmp_dir.path().join("challenge.txt.asc");

    std::fs::write(&data_path, nonce)?;

    let status = std::process::Command::new("gpg")
        .args([
            "--batch",
            "--yes",
            "--detach-sign",
            "--armor",
            "-u",
            gpg_key_id,
            "-o",
            sig_path.to_str().unwrap_or("challenge.txt.asc"),
            data_path.to_str().unwrap_or("challenge.txt"),
        ])
        .stdout(std::process::Stdio::null())
        .stderr(std::process::Stdio::piped())
        .status()
        .map_err(|e| anyhow::anyhow!("gpg not found: {e} — is GPG installed?"))?;

    if !status.success() {
        anyhow::bail!(
            "gpg --detach-sign failed — check that key '{}' is available",
            gpg_key_id
        );
    }

    let signature = std::fs::read_to_string(&sig_path)
        .map_err(|e| anyhow::anyhow!("failed to read GPG signature: {e}"))?;

    Ok(signature)
}

// ─────────────────────────────────────────────────────
// Tests
// ─────────────────────────────────────────────────────

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn scaffold_creates_structure() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("test-config"), None, &printer).unwrap();

        assert!(dir.path().join("cfgd.yaml").exists());
        assert!(dir.path().join("profiles").is_dir());
        assert!(dir.path().join("modules").is_dir());
        assert!(!dir.path().join("files").exists());
        assert!(dir.path().join(".gitignore").exists());

        let contents = std::fs::read_to_string(dir.path().join("cfgd.yaml")).unwrap();
        assert!(contents.contains("name: test-config"));
    }

    #[test]
    fn scaffold_with_theme() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("themed"), Some("minimal"), &printer).unwrap();

        let contents = std::fs::read_to_string(dir.path().join("cfgd.yaml")).unwrap();
        assert!(contents.contains("name: themed"));
        assert!(contents.contains("theme: minimal"));
    }

    #[test]
    fn scaffold_uses_dir_name_as_default() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), None, None, &printer).unwrap();

        let contents = std::fs::read_to_string(dir.path().join("cfgd.yaml")).unwrap();
        // Should use the tempdir name
        assert!(contents.contains("name:"));
    }

    #[test]
    fn ensure_config_file_creates_new() {
        let dir = tempfile::tempdir().unwrap();
        let config_path = dir.path().join("cfgd.yaml");

        ensure_config_file(
            dir.path(),
            &config_path,
            "work",
            Some("https://github.com/test/init-cfg.git"),
            "master",
            None,
        )
        .unwrap();

        assert!(config_path.exists());
        let contents = std::fs::read_to_string(&config_path).unwrap();
        assert!(contents.contains("profile: work"));
        assert!(contents.contains("https://github.com/test/init-cfg.git"));
    }

    #[test]
    fn ensure_config_file_updates_existing() {
        let dir = tempfile::tempdir().unwrap();
        let config_path = dir.path().join("cfgd.yaml");

        std::fs::write(
            &config_path,
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec:\n  profile: default\n",
        )
        .unwrap();

        ensure_config_file(dir.path(), &config_path, "work", None, "master", None).unwrap();

        let cfg = config::load_config(&config_path).unwrap();
        assert_eq!(cfg.spec.profile.as_deref(), Some("work"));
    }

    #[test]
    fn ensure_config_file_no_update_if_same_profile() {
        let dir = tempfile::tempdir().unwrap();
        let config_path = dir.path().join("cfgd.yaml");

        let original = "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec:\n  profile: default\n";
        std::fs::write(&config_path, original).unwrap();

        ensure_config_file(dir.path(), &config_path, "default", None, "master", None).unwrap();

        let contents = std::fs::read_to_string(&config_path).unwrap();
        assert_eq!(contents, original);
    }

    #[test]
    fn ensure_config_file_with_branch_and_theme() {
        let dir = tempfile::tempdir().unwrap();
        let config_path = dir.path().join("cfgd.yaml");

        ensure_config_file(
            dir.path(),
            &config_path,
            "work",
            Some("https://github.com/test/cfg.git"),
            "develop",
            Some("minimal"),
        )
        .unwrap();

        let contents = std::fs::read_to_string(&config_path).unwrap();
        assert!(contents.contains("branch: develop"));
        assert!(contents.contains("theme: minimal"));
    }

    #[test]
    fn count_packages_empty() {
        let spec = config::ProfileSpec::default();
        assert_eq!(count_packages(&spec), 0);
    }

    #[test]
    fn count_packages_with_various() {
        let spec = config::ProfileSpec {
            packages: Some(config::PackagesSpec {
                brew: Some(config::BrewSpec {
                    formulae: vec!["rg".into(), "fd".into()],
                    casks: vec!["firefox".into()],
                    ..Default::default()
                }),
                cargo: Some(config::CargoSpec {
                    file: None,
                    packages: vec!["bat".into()],
                }),
                ..Default::default()
            }),
            ..Default::default()
        };
        assert_eq!(count_packages(&spec), 4);
    }

    #[test]
    fn profile_switch_via_config_update() {
        let dir = tempfile::tempdir().unwrap();
        let profiles_dir = dir.path().join("profiles");
        std::fs::create_dir_all(&profiles_dir).unwrap();
        std::fs::write(
            profiles_dir.join("work.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Profile\nmetadata:\n  name: work\nspec:\n  env: []\n",
        )
        .unwrap();

        let config_path = dir.path().join("cfgd.yaml");
        std::fs::write(
            &config_path,
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec:\n  profile: default\n",
        )
        .unwrap();

        ensure_config_file(dir.path(), &config_path, "work", None, "master", None).unwrap();

        let cfg = config::load_config(&config_path).unwrap();
        assert_eq!(cfg.spec.profile.as_deref(), Some("work"));
    }

    #[test]
    fn regenerate_workflow_empty_repo() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::create_dir_all(dir.path().join("profiles")).unwrap();
        std::fs::create_dir_all(dir.path().join("modules")).unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        regenerate_workflow(dir.path(), &printer).unwrap();

        // No profiles or modules → no workflow generated
        assert!(
            !dir.path()
                .join(".github/workflows/cfgd-release.yml")
                .exists()
        );
    }

    #[test]
    fn regenerate_workflow_with_profile() {
        let dir = tempfile::tempdir().unwrap();
        let profiles_dir = dir.path().join("profiles");
        std::fs::create_dir_all(&profiles_dir).unwrap();
        std::fs::create_dir_all(dir.path().join("modules")).unwrap();
        std::fs::write(
            profiles_dir.join("base.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Profile\nmetadata:\n  name: base\nspec: {}\n",
        )
        .unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        regenerate_workflow(dir.path(), &printer).unwrap();

        let workflow = dir.path().join(".github/workflows/cfgd-release.yml");
        assert!(workflow.exists());
        let contents = std::fs::read_to_string(&workflow).unwrap();
        assert!(contents.contains("base"));
    }

    #[test]
    fn scaffold_includes_default_theme() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("test"), None, &printer).unwrap();
        let cfg = config::load_config(&dir.path().join("cfgd.yaml")).unwrap();
        assert_eq!(cfg.spec.theme.unwrap().name, "default");
    }

    #[test]
    fn scaffold_with_custom_theme() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("test"), Some("minimal"), &printer).unwrap();
        let cfg = config::load_config(&dir.path().join("cfgd.yaml")).unwrap();
        assert_eq!(cfg.spec.theme.unwrap().name, "minimal");
    }

    #[test]
    fn pick_profile_single_profile() {
        let dir = tempfile::tempdir().unwrap();
        let profiles_dir = dir.path().join("profiles");
        std::fs::create_dir_all(&profiles_dir).unwrap();
        std::fs::write(
            profiles_dir.join("base.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Profile\nmetadata:\n  name: base\nspec: {}\n",
        )
        .unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result = pick_profile(&profiles_dir, &printer).unwrap();
        assert_eq!(result, "base");
    }

    #[test]
    fn pick_profile_no_profiles_errors() {
        let dir = tempfile::tempdir().unwrap();
        let profiles_dir = dir.path().join("profiles");
        std::fs::create_dir_all(&profiles_dir).unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let err = pick_profile(&profiles_dir, &printer).unwrap_err();
        assert!(
            err.to_string().contains("No profiles found"),
            "should report no profiles, got: {err}"
        );
    }

    #[test]
    fn pick_profile_no_dir_errors() {
        let dir = tempfile::tempdir().unwrap();
        let profiles_dir = dir.path().join("profiles");
        // Don't create the dir

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let err = pick_profile(&profiles_dir, &printer).unwrap_err();
        assert!(
            err.to_string().contains("No profiles directory"),
            "should report missing dir, got: {err}"
        );
    }

    #[test]
    fn is_git_source_detects_urls() {
        assert!(is_git_source("https://github.com/user/repo"));
        assert!(is_git_source("http://github.com/user/repo"));
        assert!(is_git_source("git@github.com:user/repo.git"));
        assert!(is_git_source("ssh://git@github.com/user/repo"));
        assert!(is_git_source("git://github.com/user/repo"));
        assert!(is_git_source("/some/local/path.git"));
    }

    #[test]
    fn is_git_source_detects_local_git_repo() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::create_dir(dir.path().join(".git")).unwrap();
        assert!(is_git_source(&dir.path().display().to_string()));
    }

    #[test]
    fn is_git_source_rejects_plain_paths() {
        assert!(!is_git_source("/home/user/config"));
        assert!(!is_git_source("~/my-config"));
        assert!(!is_git_source("./relative/path"));
        assert!(!is_git_source("config"));
    }

    #[test]
    fn resolve_from_local_path_with_config() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::write(
            dir.path().join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec: {}\n",
        )
        .unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result = resolve_from(&dir.path().display().to_string(), None, "master", &printer);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), dir.path());
    }

    #[test]
    fn resolve_from_local_path_missing_config_errors() {
        let dir = tempfile::tempdir().unwrap();
        // No cfgd.yaml

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result = resolve_from(&dir.path().display().to_string(), None, "master", &printer);
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("No cfgd.yaml"));
    }

    #[test]
    fn resolve_from_nonexistent_path_errors() {
        let dir = tempfile::tempdir().unwrap();
        let nonexistent = dir.path().join("does-not-exist");
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result = resolve_from(&nonexistent.display().to_string(), None, "master", &printer);
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("does not exist"));
    }

    #[test]
    fn check_prerequisites_returns_true_when_git_available() {
        // git should be available in CI and dev environments
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result = check_prerequisites(&printer);
        if cfgd_core::command_available("git") {
            assert!(
                result,
                "check_prerequisites should return true when git is available"
            );
        } else {
            assert!(
                !result,
                "check_prerequisites should return false when git is missing"
            );
        }
    }

    #[test]
    fn cmd_init_scaffolds_local_directory() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("my-config");
        std::fs::create_dir_all(&target).unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let args = InitArgs {
            path: Some(target.to_str().unwrap()),
            from: None,
            branch: "master",
            name: Some("test-init"),
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        let result = cmd_init(&printer, &args);
        assert!(result.is_ok(), "cmd_init failed: {:?}", result.err());

        // Verify scaffolded files exist and have expected content
        let cfg = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            cfg.contains("name: test-init"),
            "cfgd.yaml should contain the name"
        );
        assert!(
            cfg.contains("cfgd.io/v1alpha1"),
            "cfgd.yaml should have apiVersion"
        );
        assert!(target.join("profiles").is_dir());
        assert!(target.join("modules").is_dir());
        let gitignore = std::fs::read_to_string(target.join(".gitignore")).unwrap();
        assert!(
            gitignore.contains("!cfgd.yaml"),
            ".gitignore should allow cfgd.yaml"
        );
        assert!(target.join("README.md").exists());

        // Verify git repo was initialized
        assert!(target.join(".git").exists());
    }

    #[test]
    fn cmd_init_skips_if_already_initialized() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("existing");
        std::fs::create_dir_all(&target).unwrap();
        std::fs::write(
            target.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: existing\nspec: {}\n",
        )
        .unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let args = InitArgs {
            path: Some(target.to_str().unwrap()),
            from: None,
            branch: "master",
            name: None,
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        let result = cmd_init(&printer, &args);
        assert!(result.is_ok());
        // cfgd.yaml should be unchanged (not overwritten)
        let contents = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(contents.contains("name: existing"));
    }

    #[test]
    fn cmd_init_creates_directory_if_missing() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("new-config");
        assert!(!target.exists());

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let args = InitArgs {
            path: Some(target.to_str().unwrap()),
            from: None,
            branch: "master",
            name: Some("fresh"),
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: Some("minimal"),
            apply_profile: None,
            apply_modules: &[],
        };

        let result = cmd_init(&printer, &args);
        assert!(result.is_ok(), "cmd_init failed: {:?}", result.err());
        assert!(target.exists());
        assert!(target.join("cfgd.yaml").exists());

        let contents = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(contents.contains("theme: minimal"));
    }

    #[test]
    fn clone_into_local_repo() {
        let dir = tempfile::tempdir().unwrap();

        // Create a source repo with a commit
        let origin = dir.path().join("origin");
        let repo = git2::Repository::init(&origin).unwrap();
        let sig = git2::Signature::now("Test", "test@example.com").unwrap();
        std::fs::write(
            origin.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec: {}\n",
        )
        .unwrap();
        let mut index = repo.index().unwrap();
        index.add_path(std::path::Path::new("cfgd.yaml")).unwrap();
        index.write().unwrap();
        let tree_id = index.write_tree().unwrap();
        let tree = repo.find_tree(tree_id).unwrap();
        repo.commit(Some("HEAD"), &sig, &sig, "init", &tree, &[])
            .unwrap();

        let target = dir.path().join("clone");
        std::fs::create_dir_all(&target).unwrap();

        let (printer, buf) = Printer::for_test();
        clone_into(&target, &origin.display().to_string(), "master", &printer).unwrap();

        assert!(target.join(".git").exists(), "should create .git directory");
        let cfg = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            cfg.contains("name: test"),
            "cloned cfgd.yaml should contain the name"
        );

        let output = buf.lock().unwrap();
        assert!(output.contains("Cloned"), "should report successful clone");
    }

    #[test]
    fn clone_into_skips_if_already_cloned() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("clone");
        std::fs::create_dir_all(target.join(".git")).unwrap();

        let (printer, buf) = Printer::for_test();
        // Should return Ok without actually cloning
        clone_into(
            &target,
            "https://example.com/nonexistent",
            "master",
            &printer,
        )
        .unwrap();

        let output = buf.lock().unwrap();
        assert!(
            output.contains("already exists"),
            "should report repo already exists, got: {output}"
        );
    }

    #[test]
    fn resolve_from_git_source_local_repo() {
        let dir = tempfile::tempdir().unwrap();

        // Create a source repo
        let origin = dir.path().join("origin");
        let repo = git2::Repository::init(&origin).unwrap();
        let sig = git2::Signature::now("Test", "test@example.com").unwrap();
        std::fs::write(
            origin.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec: {}\n",
        )
        .unwrap();
        let mut index = repo.index().unwrap();
        index.add_path(std::path::Path::new("cfgd.yaml")).unwrap();
        index.write().unwrap();
        let tree_id = index.write_tree().unwrap();
        let tree = repo.find_tree(tree_id).unwrap();
        repo.commit(Some("HEAD"), &sig, &sig, "init", &tree, &[])
            .unwrap();

        let target = dir.path().join("target");
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result = resolve_from(
            &origin.display().to_string(),
            Some(&target),
            "master",
            &printer,
        )
        .unwrap();

        assert_eq!(result, target, "should return the target path");
        let cfg = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            cfg.contains("name: test"),
            "cloned cfgd.yaml should have the source content"
        );
    }

    #[test]
    fn resolve_from_already_initialized_git_source() {
        let dir = tempfile::tempdir().unwrap();

        // Create target with existing cfgd.yaml
        let target = dir.path().join("already-init");
        std::fs::create_dir_all(&target).unwrap();
        std::fs::write(
            target.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec: {}\n",
        )
        .unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        // Using a git URL (https://) triggers the git source path
        let result = resolve_from(
            "https://example.com/repo.git",
            Some(&target),
            "master",
            &printer,
        );
        assert!(result.is_ok());
        // Should return the target path without re-cloning
        assert_eq!(result.unwrap(), target);
    }

    #[test]
    fn scaffold_creates_readme_with_name() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("my-dotfiles"), None, &printer).unwrap();

        let readme = std::fs::read_to_string(dir.path().join("README.md")).unwrap();
        assert!(
            readme.contains("my-dotfiles"),
            "README should contain the config name"
        );
    }

    #[test]
    fn scaffold_creates_gitignore() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("test"), None, &printer).unwrap();

        let gitignore = std::fs::read_to_string(dir.path().join(".gitignore")).unwrap();
        assert!(gitignore.contains("!cfgd.yaml"));
        assert!(gitignore.contains("!profiles/"));
        assert!(gitignore.contains("!modules/"));
    }

    #[test]
    fn scaffold_creates_workflow() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("test"), None, &printer).unwrap();

        let workflow_path = dir.path().join(".github/workflows/cfgd-release.yml");
        let workflow = std::fs::read_to_string(&workflow_path).unwrap();
        assert!(workflow.contains("cfgd"), "workflow should reference cfgd");
    }

    #[test]
    fn cmd_init_with_from_local_path() {
        let dir = tempfile::tempdir().unwrap();
        let source = dir.path().join("source");
        std::fs::create_dir_all(&source).unwrap();
        std::fs::write(
            source.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: source\nspec: {}\n",
        )
        .unwrap();

        let (printer, buf) = Printer::for_test();
        let source_str = source.display().to_string();
        let args = InitArgs {
            path: None,
            from: Some(&source_str),
            branch: "master",
            name: None,
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        cmd_init(&printer, &args).unwrap();

        let output = buf.lock().unwrap();
        assert!(
            output.contains("Initialize") || output.contains("Initialized"),
            "should show init header, got: {output}"
        );
    }

    #[test]
    fn ensure_config_file_creates_without_origin() {
        let dir = tempfile::tempdir().unwrap();
        let config_path = dir.path().join("cfgd.yaml");

        ensure_config_file(dir.path(), &config_path, "default", None, "master", None).unwrap();

        let contents = std::fs::read_to_string(&config_path).unwrap();
        assert!(contents.contains("profile: default"));
        // No origin section when from_url is None
        assert!(!contents.contains("origin:"));
    }

    #[test]
    fn count_packages_npm_and_pipx() {
        let spec = config::ProfileSpec {
            packages: Some(config::PackagesSpec {
                npm: Some(config::NpmSpec {
                    global: vec!["prettier".into(), "eslint".into()],
                    ..Default::default()
                }),
                pipx: vec!["black".into()],
                ..Default::default()
            }),
            ..Default::default()
        };
        assert_eq!(count_packages(&spec), 3);
    }

    #[test]
    fn count_packages_dnf() {
        let spec = config::ProfileSpec {
            packages: Some(config::PackagesSpec {
                dnf: vec!["vim".into(), "tmux".into()],
                ..Default::default()
            }),
            ..Default::default()
        };
        assert_eq!(count_packages(&spec), 2);
    }

    // ─── cmd_init — scaffold to new directory ──────────────────

    #[test]
    fn cmd_init_scaffold_to_new_dir() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("new-config");

        let (printer, buf) = Printer::for_test();
        let target_str = target.display().to_string();
        let args = InitArgs {
            path: Some(&target_str),
            from: None,
            branch: "master",
            name: Some("my-machine"),
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        cmd_init(&printer, &args).unwrap();

        // Verify scaffolded structure
        assert!(target.join("cfgd.yaml").exists(), "should create cfgd.yaml");
        assert!(target.join("profiles").exists(), "should create profiles/");
        assert!(target.join("modules").exists(), "should create modules/");
        assert!(
            target.join(".gitignore").exists(),
            "should create .gitignore"
        );

        let config = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            config.contains("my-machine"),
            "config should contain the name, got: {config}"
        );

        let output = buf.lock().unwrap();
        assert!(
            output.contains("Initialized"),
            "should show init success, got: {output}"
        );
    }

    #[test]
    fn cmd_init_already_initialized() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("existing");
        std::fs::create_dir_all(&target).unwrap();
        std::fs::write(
            target.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: existing\nspec: {}\n",
        )
        .unwrap();

        let (printer, buf) = Printer::for_test();
        let target_str = target.display().to_string();
        let args = InitArgs {
            path: Some(&target_str),
            from: None,
            branch: "master",
            name: None,
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        cmd_init(&printer, &args).unwrap();

        let output = buf.lock().unwrap();
        assert!(
            output.contains("Already initialized"),
            "should report already initialized, got: {output}"
        );
    }

    #[test]
    fn cmd_init_with_theme() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("themed");

        let (printer, _buf) = Printer::for_test();
        let target_str = target.display().to_string();
        let args = InitArgs {
            path: Some(&target_str),
            from: None,
            branch: "master",
            name: None,
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: Some("nord"),
            apply_profile: None,
            apply_modules: &[],
        };

        cmd_init(&printer, &args).unwrap();

        let config = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            config.contains("nord"),
            "config should contain the theme, got: {config}"
        );
    }

    // ─── resolve_from — local path variants ────────────────────

    #[test]
    fn resolve_from_local_path_valid() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::write(
            dir.path().join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec: {}\n",
        )
        .unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result =
            resolve_from(&dir.path().display().to_string(), None, "master", &printer).unwrap();
        assert_eq!(result, dir.path());
    }

    #[test]
    fn resolve_from_local_path_no_config_fails() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        let err =
            resolve_from(&dir.path().display().to_string(), None, "master", &printer).unwrap_err();
        assert!(
            err.to_string().contains("No cfgd.yaml"),
            "should report missing cfgd.yaml, got: {err}"
        );
    }

    #[test]
    fn resolve_from_nonexistent_path_fails() {
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let err = resolve_from("/nonexistent/path/xyz", None, "master", &printer).unwrap_err();
        assert!(
            err.to_string().contains("does not exist"),
            "should report path does not exist, got: {err}"
        );
    }

    // ─── is_git_source — comprehensive coverage ────────────────

    #[test]
    fn is_git_source_https() {
        assert!(is_git_source("https://github.com/user/repo"));
        assert!(is_git_source("https://github.com/user/repo.git"));
    }

    #[test]
    fn is_git_source_ssh() {
        assert!(is_git_source("ssh://git@github.com/user/repo"));
        assert!(is_git_source("git@github.com:user/repo.git"));
    }

    #[test]
    fn is_git_source_git_protocol() {
        assert!(is_git_source("git://github.com/user/repo"));
    }

    #[test]
    fn is_git_source_dot_git_suffix() {
        assert!(is_git_source("anything.git"));
    }

    #[test]
    fn is_git_source_local_plain_dir_not_git() {
        let dir = tempfile::tempdir().unwrap();
        assert!(
            !is_git_source(&dir.path().display().to_string()),
            "plain directory without .git should not be a git source"
        );
    }

    #[test]
    fn is_git_source_local_git_repo() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::create_dir_all(dir.path().join(".git")).unwrap();
        assert!(
            is_git_source(&dir.path().display().to_string()),
            "directory with .git should be a git source"
        );
    }

    // ─── scaffold — content verification ───────────────────────

    #[test]
    fn scaffold_gitignore_content() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("test"), None, &printer).unwrap();

        let gitignore = std::fs::read_to_string(dir.path().join(".gitignore")).unwrap();
        assert!(
            gitignore.contains("!profiles/**"),
            "should unignore profiles"
        );
        assert!(gitignore.contains("!modules/**"), "should unignore modules");
        assert!(gitignore.contains("!.github/"), "should unignore .github");
    }

    #[test]
    fn scaffold_config_content() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(dir.path(), Some("my-dots"), Some("catppuccin"), &printer).unwrap();

        let config = std::fs::read_to_string(dir.path().join("cfgd.yaml")).unwrap();
        assert!(config.contains("my-dots"), "should use custom name");
        assert!(config.contains("catppuccin"), "should use custom theme");
        assert!(
            config.contains("Symlink"),
            "should set default file strategy"
        );
    }

    #[test]
    fn scaffold_uses_dir_name_when_no_name() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("cool-dotfiles");
        std::fs::create_dir_all(&target).unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);

        scaffold(&target, None, None, &printer).unwrap();

        let config = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            config.contains("cool-dotfiles"),
            "should use directory name, got: {config}"
        );
    }

    // ─── pick_profile — edge cases ─────────────────────────────

    #[test]
    fn pick_profile_single_profile_auto_selects() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::create_dir_all(dir.path()).unwrap();
        std::fs::write(
            dir.path().join("default.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Profile\nmetadata:\n  name: default\nspec: {}\n",
        )
        .unwrap();

        let (printer, buf) = Printer::for_test();
        let result = pick_profile(dir.path(), &printer).unwrap();
        assert_eq!(result, "default");

        let output = buf.lock().unwrap();
        assert!(
            output.contains("Using only available profile: default"),
            "should auto-select single profile, got: {output}"
        );
    }

    #[test]
    fn pick_profile_no_dir_fails() {
        let dir = tempfile::tempdir().unwrap();
        let nonexistent = dir.path().join("nope");
        let (printer, _buf) = Printer::for_test();

        let err = pick_profile(&nonexistent, &printer).unwrap_err();
        assert!(
            err.to_string().contains("No profiles directory"),
            "should report no profiles dir, got: {err}"
        );
    }

    #[test]
    fn pick_profile_empty_dir_fails() {
        let dir = tempfile::tempdir().unwrap();
        let (printer, _buf) = Printer::for_test();

        let err = pick_profile(dir.path(), &printer).unwrap_err();
        assert!(
            err.to_string().contains("No profiles found"),
            "should report no profiles, got: {err}"
        );
    }

    // ─── regenerate_workflow ────────────────────────────────────

    #[test]
    fn regenerate_workflow_skips_empty() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::create_dir_all(dir.path().join("profiles")).unwrap();
        std::fs::create_dir_all(dir.path().join("modules")).unwrap();
        let (printer, _buf) = Printer::for_test();

        regenerate_workflow(dir.path(), &printer).unwrap();

        // No workflow should be generated for empty project
        assert!(
            !dir.path()
                .join(".github/workflows/cfgd-release.yml")
                .exists(),
            "should not create workflow for empty project"
        );
    }

    #[test]
    fn regenerate_workflow_creates_for_content() {
        let dir = tempfile::tempdir().unwrap();
        let profiles_dir = dir.path().join("profiles");
        std::fs::create_dir_all(&profiles_dir).unwrap();
        std::fs::write(
            profiles_dir.join("default.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Profile\nmetadata:\n  name: default\nspec: {}\n",
        )
        .unwrap();
        std::fs::create_dir_all(dir.path().join("modules")).unwrap();

        let (printer, _buf) = Printer::for_test();
        regenerate_workflow(dir.path(), &printer).unwrap();

        let workflow_path = dir.path().join(".github/workflows/cfgd-release.yml");
        assert!(workflow_path.exists(), "should create workflow");
        let content = std::fs::read_to_string(&workflow_path).unwrap();
        assert!(content.contains("cfgd"), "workflow should reference cfgd");
    }

    // ─── ensure_config_file — branch and origin ────────────────

    #[test]
    fn ensure_config_file_with_origin() {
        let dir = tempfile::tempdir().unwrap();
        let config_path = dir.path().join("cfgd.yaml");

        ensure_config_file(
            dir.path(),
            &config_path,
            "work",
            Some("https://github.com/team/config"),
            "main",
            None,
        )
        .unwrap();

        let contents = std::fs::read_to_string(&config_path).unwrap();
        assert!(contents.contains("profile: work"), "should set profile");
        assert!(
            contents.contains("origin:"),
            "should have origin section for git URL"
        );
        assert!(
            contents.contains("https://github.com/team/config"),
            "should contain the URL"
        );
        assert!(
            contents.contains("branch: main"),
            "should contain the branch"
        );
    }

    #[test]
    fn ensure_config_file_with_theme() {
        let dir = tempfile::tempdir().unwrap();
        let config_path = dir.path().join("cfgd.yaml");

        ensure_config_file(
            dir.path(),
            &config_path,
            "default",
            None,
            "master",
            Some("dracula"),
        )
        .unwrap();

        let contents = std::fs::read_to_string(&config_path).unwrap();
        assert!(
            contents.contains("dracula"),
            "should use custom theme, got: {contents}"
        );
    }

    // ─── count_packages — additional cases ─────────────────────

    #[test]
    fn count_packages_no_packages_spec() {
        let spec = config::ProfileSpec {
            packages: None,
            ..Default::default()
        };
        assert_eq!(count_packages(&spec), 0);
    }

    #[test]
    fn count_packages_brew_formulae_and_casks() {
        let spec = config::ProfileSpec {
            packages: Some(config::PackagesSpec {
                brew: Some(config::BrewSpec {
                    file: None,
                    taps: vec![],
                    formulae: vec!["curl".into(), "vim".into()],
                    casks: vec!["firefox".into()],
                }),
                ..Default::default()
            }),
            ..Default::default()
        };
        assert_eq!(count_packages(&spec), 3);
    }

    #[test]
    fn count_packages_apt_and_cargo() {
        let spec = config::ProfileSpec {
            packages: Some(config::PackagesSpec {
                apt: Some(config::AptSpec {
                    packages: vec!["build-essential".into()],
                    ..Default::default()
                }),
                cargo: Some(config::CargoSpec {
                    file: None,
                    packages: vec!["ripgrep".into(), "fd-find".into()],
                }),
                ..Default::default()
            }),
            ..Default::default()
        };
        assert_eq!(count_packages(&spec), 3);
    }

    // ─── is_git_source — additional edge cases ────────────────────

    #[test]
    fn is_git_source_http_url() {
        assert!(is_git_source("http://internal.host/repo"));
    }

    #[test]
    fn is_git_source_empty_string() {
        assert!(!is_git_source(""));
    }

    #[test]
    fn is_git_source_relative_path_not_git() {
        assert!(!is_git_source("relative/path"));
    }

    #[test]
    fn is_git_source_dot_git_middle_not_matched_as_suffix() {
        // Only .git at the END matters
        assert!(!is_git_source("something.github"));
    }

    #[test]
    fn is_git_source_bare_name_not_git() {
        assert!(!is_git_source("myconfig"));
    }

    #[test]
    fn is_git_source_file_ending_in_dot_git() {
        assert!(is_git_source("file:///path/to/repo.git"));
    }

    // ─── resolve_from — additional cases ──────────────────────────

    #[test]
    fn resolve_from_local_path_returns_canonicalized_path() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::write(
            dir.path().join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec: {}\n",
        )
        .unwrap();

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result =
            resolve_from(&dir.path().display().to_string(), None, "main", &printer).unwrap();
        // The result should be a valid path containing cfgd.yaml
        assert!(result.join("cfgd.yaml").exists());
    }

    #[test]
    fn resolve_from_git_source_with_target_creates_dir() {
        let dir = tempfile::tempdir().unwrap();

        // Create a source repo
        let origin = dir.path().join("origin");
        let repo = git2::Repository::init(&origin).unwrap();
        let sig = git2::Signature::now("Test", "test@example.com").unwrap();
        std::fs::write(
            origin.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: test\nspec: {}\n",
        )
        .unwrap();
        let mut index = repo.index().unwrap();
        index.add_path(std::path::Path::new("cfgd.yaml")).unwrap();
        index.write().unwrap();
        let tree_id = index.write_tree().unwrap();
        let tree = repo.find_tree(tree_id).unwrap();
        repo.commit(Some("HEAD"), &sig, &sig, "init", &tree, &[])
            .unwrap();

        let target = dir.path().join("new-target");
        assert!(!target.exists());

        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        let result = resolve_from(
            &origin.display().to_string(),
            Some(&target),
            "master",
            &printer,
        )
        .unwrap();

        assert_eq!(result, target);
        assert!(target.join("cfgd.yaml").exists());
    }

    // ─── scaffold — idempotency and content ───────────────────────

    #[test]
    fn scaffold_config_has_api_version() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        scaffold(dir.path(), Some("my-cfg"), None, &printer).unwrap();

        let config = std::fs::read_to_string(dir.path().join("cfgd.yaml")).unwrap();
        assert!(
            config.contains("apiVersion: cfgd.io/v1alpha1"),
            "config should have apiVersion"
        );
        assert!(
            config.contains("kind: Config"),
            "config should have kind: Config"
        );
        assert!(
            config.contains("fileStrategy: Symlink"),
            "config should set default file strategy"
        );
    }

    #[test]
    fn scaffold_readme_contains_structure_docs() {
        let dir = tempfile::tempdir().unwrap();
        let printer = Printer::new(cfgd_core::output::Verbosity::Quiet);
        scaffold(dir.path(), Some("documented"), None, &printer).unwrap();

        let readme = std::fs::read_to_string(dir.path().join("README.md")).unwrap();
        assert!(
            readme.contains("profiles/"),
            "README should mention profiles"
        );
        assert!(readme.contains("modules/"), "README should mention modules");
        assert!(
            readme.contains("cfgd.yaml"),
            "README should mention cfgd.yaml"
        );
        assert!(
            readme.contains("documented"),
            "README should contain the config name"
        );
    }

    // ─── cmd_init — flag combinations ─────────────────────────────

    #[test]
    fn cmd_init_with_name_overrides_dir_name() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("generic-dir");

        let (printer, _buf) = Printer::for_test();
        let target_str = target.display().to_string();
        let args = InitArgs {
            path: Some(&target_str),
            from: None,
            branch: "master",
            name: Some("my-awesome-config"),
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        cmd_init(&printer, &args).unwrap();

        let config = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            config.contains("my-awesome-config"),
            "config should use the explicit name, not the dir name, got: {config}"
        );
    }

    #[test]
    fn cmd_init_creates_git_repo() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("git-init-test");

        let (printer, _buf) = Printer::for_test();
        let target_str = target.display().to_string();
        let args = InitArgs {
            path: Some(&target_str),
            from: None,
            branch: "master",
            name: Some("test"),
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        cmd_init(&printer, &args).unwrap();

        assert!(
            target.join(".git").exists(),
            "cmd_init should create a .git directory"
        );
        // Verify it's a valid git repo
        let repo = git2::Repository::open(&target);
        assert!(repo.is_ok(), "should be a valid git repository");
    }

    #[test]
    fn cmd_init_with_theme_and_name_together() {
        let dir = tempfile::tempdir().unwrap();
        let target = dir.path().join("combo-test");

        let (printer, _buf) = Printer::for_test();
        let target_str = target.display().to_string();
        let args = InitArgs {
            path: Some(&target_str),
            from: None,
            branch: "master",
            name: Some("my-workstation"),
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: Some("catppuccin"),
            apply_profile: None,
            apply_modules: &[],
        };

        cmd_init(&printer, &args).unwrap();

        let config = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            config.contains("my-workstation"),
            "config should have the name"
        );
        assert!(
            config.contains("catppuccin"),
            "config should have the theme"
        );
    }

    // ─── apply_plan — dry run and empty plan ─────────────────────

    #[test]
    fn apply_plan_empty_plan_reports_nothing_to_do() {
        let dir = tempfile::tempdir().unwrap();
        let (printer, buf) = Printer::for_test();

        let registry = super::build_registry_with_config(None);
        // Isolate the state store under the tempdir so parallel tests don't
        // contend on the shared default state database (SQLite lock contention
        // manifests as 'database is locked' on slower filesystems, e.g. macOS).
        let store = super::open_state_store(Some(dir.path())).unwrap();
        let reconciler = cfgd_core::reconciler::Reconciler::new(&registry, &store);
        let resolved = config::ResolvedProfile {
            layers: Vec::new(),
            merged: config::MergedProfile::default(),
        };

        let plan = cfgd_core::reconciler::Plan {
            phases: Vec::new(),
            warnings: Vec::new(),
        };
        let result = apply_plan(
            &plan,
            &reconciler,
            &resolved,
            dir.path(),
            false,
            false,
            &printer,
        );
        assert!(result.is_ok());

        let output = buf.lock().unwrap();
        assert!(
            output.contains("Nothing to do"),
            "should report nothing to do for empty plan, got: {output}"
        );
    }

    // ─── check_prerequisites — git availability ──────────────────

    #[test]
    fn check_prerequisites_with_test_printer() {
        let (printer, buf) = Printer::for_test();
        let result = check_prerequisites(&printer);
        let output = buf.lock().unwrap();

        if cfgd_core::command_available("git") {
            assert!(result, "should return true when git available");
            // No error output when git is available
            assert!(
                !output.contains("not installed"),
                "should not show error when git is available"
            );
        } else {
            assert!(!result, "should return false when git unavailable");
            assert!(
                output.contains("not installed"),
                "should show error when git is missing, got: {output}"
            );
        }
    }

    // ─── ensure_config_file — edge cases ─────────────────────────

    #[test]
    fn ensure_config_file_preserves_other_fields_on_profile_update() {
        let dir = tempfile::tempdir().unwrap();
        let config_path = dir.path().join("cfgd.yaml");

        // Write a config with extra fields
        let original = r#"apiVersion: cfgd.io/v1alpha1
kind: Config
metadata:
  name: my-config
spec:
  profile: old-profile
  fileStrategy: Symlink
"#;
        std::fs::write(&config_path, original).unwrap();

        ensure_config_file(
            dir.path(),
            &config_path,
            "new-profile",
            None,
            "master",
            None,
        )
        .unwrap();

        let cfg = config::load_config(&config_path).unwrap();
        assert_eq!(
            cfg.spec.profile.as_deref(),
            Some("new-profile"),
            "profile should be updated"
        );
        assert_eq!(cfg.metadata.name, "my-config", "name should be preserved");
    }

    // ─── regenerate_workflow — with modules ──────────────────────

    #[test]
    fn regenerate_workflow_with_modules_and_profiles() {
        let dir = tempfile::tempdir().unwrap();
        let profiles_dir = dir.path().join("profiles");
        let modules_dir = dir.path().join("modules");
        std::fs::create_dir_all(&profiles_dir).unwrap();
        std::fs::create_dir_all(&modules_dir).unwrap();

        // Create a profile
        std::fs::write(
            profiles_dir.join("work.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Profile\nmetadata:\n  name: work\nspec: {}\n",
        )
        .unwrap();

        // Create a module directory
        let mod_dir = modules_dir.join("git");
        std::fs::create_dir_all(&mod_dir).unwrap();
        std::fs::write(
            mod_dir.join("module.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Module\nmetadata:\n  name: git\nspec: {}\n",
        )
        .unwrap();

        let (printer, _buf) = Printer::for_test();
        regenerate_workflow(dir.path(), &printer).unwrap();

        let workflow_path = dir.path().join(".github/workflows/cfgd-release.yml");
        assert!(workflow_path.exists(), "should create workflow");
        let content = std::fs::read_to_string(&workflow_path).unwrap();
        assert!(
            content.contains("work") || content.contains("git"),
            "workflow should reference profiles or modules, got: {content}"
        );
    }

    // ─── count_packages — all managers at once ───────────────────

    #[test]
    fn count_packages_all_managers_combined() {
        let spec = config::ProfileSpec {
            packages: Some(config::PackagesSpec {
                brew: Some(config::BrewSpec {
                    formulae: vec!["git".into()],
                    casks: vec!["iterm2".into()],
                    ..Default::default()
                }),
                apt: Some(config::AptSpec {
                    packages: vec!["vim".into()],
                    ..Default::default()
                }),
                cargo: Some(config::CargoSpec {
                    file: None,
                    packages: vec!["bat".into()],
                }),
                npm: Some(config::NpmSpec {
                    global: vec!["prettier".into()],
                    ..Default::default()
                }),
                pipx: vec!["black".into()],
                dnf: vec!["tmux".into()],
                ..Default::default()
            }),
            ..Default::default()
        };
        // brew: 1 formula + 1 cask = 2, apt: 1, cargo: 1, npm: 1, pipx: 1, dnf: 1 = 7
        assert_eq!(count_packages(&spec), 7);
    }

    // ─── cmd_init — from local path ──────────────────────────────

    #[test]
    fn cmd_init_from_local_path_uses_source_dir() {
        let dir = tempfile::tempdir().unwrap();
        let source = dir.path().join("local-source");
        std::fs::create_dir_all(&source).unwrap();
        std::fs::write(
            source.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: local\nspec: {}\n",
        )
        .unwrap();
        // Create profiles/modules so workflow step doesn't fail
        std::fs::create_dir_all(source.join("profiles")).unwrap();
        std::fs::create_dir_all(source.join("modules")).unwrap();

        let (printer, buf) = Printer::for_test();
        let source_str = source.display().to_string();
        let args = InitArgs {
            path: None,
            from: Some(&source_str),
            branch: "master",
            name: None,
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        cmd_init(&printer, &args).unwrap();

        let output = buf.lock().unwrap();
        // The init should succeed and reference the source path
        assert!(
            output.contains("Initialize")
                || output.contains("Initialized")
                || output.contains("Already"),
            "should show init output, got: {output}"
        );
    }

    // --- clone_into tests ---

    #[test]
    fn clone_into_skips_existing_git_dir() {
        let dir = tempfile::tempdir().unwrap();

        // Create a repo to serve as the target that already has .git
        let target = dir.path().join("already-cloned");
        git2::Repository::init(&target).unwrap();

        let (printer, buf) = Printer::for_test();
        clone_into(&target, "https://example.com/repo.git", "main", &printer).unwrap();

        let output = buf.lock().unwrap();
        assert!(
            output.contains("already exists"),
            "should report repo already exists, got: {output}"
        );
    }

    // --- sign_with_ssh tests ---

    #[test]
    fn sign_with_ssh_requires_ssh_keygen() {
        if !cfgd_core::command_available("ssh-keygen") {
            // If ssh-keygen not available, the function should error
            let result = sign_with_ssh("test-nonce", "/nonexistent/key");
            assert!(result.is_err());
            return;
        }
        // If ssh-keygen is available but key path is bad, it should fail gracefully
        let result = sign_with_ssh("test-nonce", "/nonexistent/key");
        assert!(result.is_err(), "should fail with nonexistent key file");
    }

    // --- sign_with_gpg tests ---

    #[test]
    fn sign_with_gpg_requires_gpg() {
        if !cfgd_core::command_available("gpg") {
            let result = sign_with_gpg("test-nonce", "DEADBEEF");
            assert!(result.is_err());
            return;
        }
        // If gpg is available but key ID is invalid, it should fail
        let result = sign_with_gpg("test-nonce", "NONEXISTENT_KEY_ID_XXXXXXXX");
        assert!(result.is_err(), "should fail with nonexistent GPG key");
    }

    // --- detect_ssh_key tests ---

    #[test]
    fn detect_ssh_key_returns_option() {
        let (printer, _buf) = Printer::for_test();
        // This will either find a key or return None — both are valid
        let result = detect_ssh_key(&printer);
        // Just verify it doesn't panic and returns a valid type
        if let Some(ref path) = result {
            assert!(!path.is_empty(), "returned path should be non-empty");
        }
    }

    // --- default_device_id ---

    #[test]
    fn default_device_id_is_nonempty() {
        let id = default_device_id();
        assert!(!id.is_empty(), "device ID should not be empty");
    }

    #[test]
    fn default_device_id_is_deterministic() {
        let id1 = default_device_id();
        let id2 = default_device_id();
        assert_eq!(id1, id2, "device ID should be deterministic");
    }

    // --- apply_plan with dry_run ---

    #[test]
    fn apply_plan_dry_run_skips_apply() {
        let dir = tempfile::tempdir().unwrap();
        let (printer, buf) = Printer::for_test();

        let registry = super::build_registry_with_config(None);
        // Isolate the state store under the tempdir so parallel tests don't
        // contend on the shared default state database.
        let store = super::open_state_store(Some(dir.path())).unwrap();
        let reconciler = cfgd_core::reconciler::Reconciler::new(&registry, &store);
        let resolved = config::ResolvedProfile {
            layers: Vec::new(),
            merged: config::MergedProfile::default(),
        };

        // Create a plan with at least one action so dry_run actually has something to skip
        let plan = cfgd_core::reconciler::Plan {
            phases: vec![cfgd_core::reconciler::Phase {
                name: cfgd_core::reconciler::PhaseName::Packages,
                actions: vec![cfgd_core::reconciler::Action::Package(
                    cfgd_core::providers::PackageAction::Install {
                        manager: "brew".to_string(),
                        packages: vec!["test-pkg".to_string()],
                        origin: "test".to_string(),
                    },
                )],
            }],
            warnings: Vec::new(),
        };

        let result = apply_plan(
            &plan,
            &reconciler,
            &resolved,
            dir.path(),
            true, // dry_run
            false,
            &printer,
        );
        assert!(result.is_ok());

        let output = buf.lock().unwrap();
        // Dry run shows the plan but does not apply
        assert!(
            output.contains("action") || output.contains("planned"),
            "should show planned actions, got: {output}"
        );
    }

    // --- cmd_init with --from pointing to git repo + custom target ---

    #[test]
    fn cmd_init_from_git_source_with_explicit_target() {
        let dir = tempfile::tempdir().unwrap();

        // Create a source git repo
        let origin = dir.path().join("origin");
        let repo = git2::Repository::init(&origin).unwrap();
        let sig = git2::Signature::now("Test", "test@example.com").unwrap();
        std::fs::write(
            origin.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: origin-cfg\nspec: {}\n",
        )
        .unwrap();
        std::fs::create_dir_all(origin.join("profiles")).unwrap();
        std::fs::create_dir_all(origin.join("modules")).unwrap();
        let mut index = repo.index().unwrap();
        index.add_path(std::path::Path::new("cfgd.yaml")).unwrap();
        index.write().unwrap();
        let tree_id = index.write_tree().unwrap();
        let tree = repo.find_tree(tree_id).unwrap();
        repo.commit(Some("HEAD"), &sig, &sig, "init", &tree, &[])
            .unwrap();

        let target = dir.path().join("my-target");
        let (printer, _buf) = Printer::for_test();
        let origin_str = origin.display().to_string();
        let target_str = target.display().to_string();
        let args = InitArgs {
            path: Some(&target_str),
            from: Some(&origin_str),
            branch: "master",
            name: None,
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: None,
            apply_profile: None,
            apply_modules: &[],
        };

        let result = cmd_init(&printer, &args);
        assert!(
            result.is_ok(),
            "cmd_init with --from git should succeed: {:?}",
            result.err()
        );
        assert!(
            target.join("cfgd.yaml").exists(),
            "should clone to target dir"
        );
    }

    // --- cmd_init with --from git and --theme ---

    #[test]
    fn cmd_init_from_git_with_theme_override() {
        let dir = tempfile::tempdir().unwrap();

        // Create origin repo
        let origin = dir.path().join("origin");
        let repo = git2::Repository::init(&origin).unwrap();
        let sig = git2::Signature::now("Test", "test@example.com").unwrap();
        std::fs::write(
            origin.join("cfgd.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Config\nmetadata:\n  name: themed-cfg\nspec:\n  theme:\n    name: default\n",
        )
        .unwrap();
        let mut index = repo.index().unwrap();
        index.add_path(std::path::Path::new("cfgd.yaml")).unwrap();
        index.write().unwrap();
        let tree_id = index.write_tree().unwrap();
        let tree = repo.find_tree(tree_id).unwrap();
        repo.commit(Some("HEAD"), &sig, &sig, "init", &tree, &[])
            .unwrap();

        let target = dir.path().join("themed-target");
        let (printer, _buf) = Printer::for_test();
        let origin_str = origin.display().to_string();
        let target_str = target.display().to_string();
        let args = InitArgs {
            path: Some(&target_str),
            from: Some(&origin_str),
            branch: "master",
            name: None,
            apply: false,
            dry_run: false,
            yes: false,
            install_daemon: false,
            theme: Some("dracula"),
            apply_profile: None,
            apply_modules: &[],
        };

        let result = cmd_init(&printer, &args);
        assert!(
            result.is_ok(),
            "cmd_init with theme override should succeed: {:?}",
            result.err()
        );

        let config = std::fs::read_to_string(target.join("cfgd.yaml")).unwrap();
        assert!(
            config.contains("dracula"),
            "theme should be overridden to dracula, got: {config}"
        );
    }

    // --- generate_release_workflow_yaml ---

    #[test]
    fn generate_release_workflow_yaml_empty_inputs() {
        let yaml = generate_release_workflow_yaml(&[], &[]);
        assert!(!yaml.is_empty(), "should produce non-empty YAML");
        assert!(yaml.contains("cfgd"), "should reference cfgd");
    }

    #[test]
    fn generate_release_workflow_yaml_with_modules() {
        let yaml = generate_release_workflow_yaml(&["git".to_string(), "tmux".to_string()], &[]);
        assert!(
            yaml.contains("git") || yaml.contains("tmux"),
            "should reference module names"
        );
    }

    #[test]
    fn generate_release_workflow_yaml_with_profiles() {
        let yaml = generate_release_workflow_yaml(&[], &["work".to_string(), "home".to_string()]);
        assert!(
            yaml.contains("work") || yaml.contains("home"),
            "should reference profile names"
        );
    }

    #[test]
    fn generate_release_workflow_yaml_with_both() {
        let yaml = generate_release_workflow_yaml(&["neovim".to_string()], &["base".to_string()]);
        assert!(!yaml.is_empty());
    }

    // --- scan_profile_names / scan_module_names ---

    #[test]
    fn scan_profile_names_filters_yaml_only() {
        let dir = tempfile::tempdir().unwrap();
        let profiles = dir.path().join("profiles");
        std::fs::create_dir_all(&profiles).unwrap();
        std::fs::write(
            profiles.join("work.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Profile\nmetadata:\n  name: work\nspec: {}\n",
        )
        .unwrap();
        std::fs::write(profiles.join("notes.txt"), "not a profile\n").unwrap();
        std::fs::write(
            profiles.join("home.yaml"),
            "apiVersion: cfgd.io/v1alpha1\nkind: Profile\nmetadata:\n  name: home\nspec: {}\n",
        )
        .unwrap();

        let names = scan_profile_names(&profiles).unwrap();
        assert!(names.contains(&"work".to_string()));
        assert!(names.contains(&"home".to_string()));
        assert!(!names.contains(&"notes".to_string()));
    }

    #[test]
    fn scan_module_names_finds_dirs_with_module_yaml() {
        let dir = tempfile::tempdir().unwrap();
        let modules = dir.path().join("modules");
        std::fs::create_dir_all(modules.join("git")).unwrap();
        std::fs::write(modules.join("git").join("module.yaml"), "spec: {}\n").unwrap();
        std::fs::create_dir_all(modules.join("empty")).unwrap();
        // empty module dir without module.yaml

        let names = scan_module_names(&modules).unwrap();
        assert!(names.contains(&"git".to_string()));
        // "empty" should not appear since it has no module.yaml
    }

    // --- list_yaml_stems ---

    #[test]
    fn list_yaml_stems_returns_sorted() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::write(dir.path().join("zebra.yaml"), "").unwrap();
        std::fs::write(dir.path().join("alpha.yaml"), "").unwrap();
        std::fs::write(dir.path().join("middle.yaml"), "").unwrap();

        let stems = super::list_yaml_stems(dir.path()).unwrap();
        assert_eq!(stems, vec!["alpha", "middle", "zebra"]);
    }

    #[test]
    fn list_yaml_stems_ignores_non_yaml() {
        let dir = tempfile::tempdir().unwrap();
        std::fs::write(dir.path().join("good.yaml"), "").unwrap();
        std::fs::write(dir.path().join("bad.txt"), "").unwrap();
        std::fs::write(dir.path().join("also.json"), "").unwrap();

        let stems = super::list_yaml_stems(dir.path()).unwrap();
        assert_eq!(stems, vec!["good"]);
    }

    #[test]
    fn list_yaml_stems_empty_dir() {
        let dir = tempfile::tempdir().unwrap();
        let stems = super::list_yaml_stems(dir.path()).unwrap();
        assert!(stems.is_empty());
    }
}
