bashrs 6.66.0

Rust-to-Shell transpiler for deterministic bootstrap scripts
use crate::models::{Error, Result};
use std::fs;
use std::path::{Path, PathBuf};

pub(crate) fn format_command(
    inputs: &[PathBuf],
    check: bool,
    dry_run: bool,
    output: Option<&Path>,
) -> Result<()> {
    let mut all_formatted = true;

    for input_path in inputs {
        let (source, formatted) = format_read_and_format(input_path)?;

        if check {
            if !format_check_file(input_path, &source, &formatted) {
                all_formatted = false;
            }
        } else if dry_run {
            format_dry_run_file(input_path, &source, &formatted);
        } else {
            format_apply_file(input_path, &source, &formatted, output)?;
        }
    }

    if check && !all_formatted {
        return Err(Error::Internal(
            "Files are not properly formatted. Run without --check to fix.".to_string(),
        ));
    }

    Ok(())
}

pub(crate) fn format_read_and_format(input_path: &Path) -> Result<(String, String)> {
    use crate::bash_quality::Formatter;

    let config = format_load_config(input_path);
    let mut formatter = Formatter::with_config(config);

    let source = fs::read_to_string(input_path)
        .map_err(|e| Error::Internal(format!("Failed to read {}: {}", input_path.display(), e)))?;
    let formatted = formatter.format_source(&source).map_err(|e| {
        Error::Internal(format!("Failed to format {}: {}", input_path.display(), e))
    })?;

    Ok((source, formatted))
}

pub(crate) fn format_load_config(input_path: &Path) -> crate::bash_quality::FormatterConfig {
    use crate::bash_quality::FormatterConfig;

    if let Some(parent) = input_path.parent() {
        let script_dir_config = parent.join(".bashrs-fmt.toml");
        if script_dir_config.exists() {
            return FormatterConfig::from_file(&script_dir_config).unwrap_or_default();
        }
    }
    FormatterConfig::from_file(".bashrs-fmt.toml").unwrap_or_default()
}

pub(crate) fn format_check_file(input_path: &Path, source: &str, formatted: &str) -> bool {
    if source.trim() == formatted.trim() {
        println!("{} is properly formatted", input_path.display());
        true
    } else {
        println!("{} is not properly formatted", input_path.display());
        false
    }
}

pub(crate) fn format_dry_run_file(input_path: &Path, source: &str, formatted: &str) {
    println!("Would format: {}", input_path.display());
    if source.trim() != formatted.trim() {
        println!("  Changes detected");
    } else {
        println!("  No changes needed");
    }
}

pub(crate) fn format_apply_file(
    input_path: &Path,
    _source: &str,
    formatted: &str,
    output: Option<&Path>,
) -> Result<()> {
    if let Some(out_path) = output {
        fs::write(out_path, formatted).map_err(|e| {
            Error::Internal(format!("Failed to write {}: {}", out_path.display(), e))
        })?;
        println!(
            "✓ Formatted {} -> {}",
            input_path.display(),
            out_path.display()
        );
    } else {
        fs::write(input_path, formatted).map_err(|e| {
            Error::Internal(format!("Failed to write {}: {}", input_path.display(), e))
        })?;
        println!("✓ Formatted {}", input_path.display());
    }
    Ok(())
}