git-send 0.1.6

Commit and push changes with a single command
//! Output handling and formatting

use colored::Colorize;
use std::io::{self, Write};

use crate::types::Summary;

/// Output helper for colored messages
pub struct Output {
    quiet: bool,
    json: bool,
}

impl Output {
    pub const fn new(quiet: bool, json: bool) -> Self {
        Self { quiet, json }
    }

    pub fn success(&self, msg: &str) {
        if self.quiet {
            return;
        }
        println!("{}", msg.green().bold());
    }

    pub fn warning(&self, msg: &str) {
        if self.quiet {
            return;
        }
        eprintln!("{}", msg.yellow().bold());
    }

    pub fn error(&self, msg: &str) {
        // Note: self is not used, but kept for API consistency
        let _ = self;
        eprintln!("{}", msg.red().bold());
    }

    pub fn info(&self, msg: &str) {
        if self.quiet {
            return;
        }
        println!("{}", msg.cyan());
    }

    pub fn progress(&self, msg: &str) {
        if self.quiet {
            return;
        }
        print!("{}", msg.blue());
        io::stdout().flush().ok();
    }

    pub fn println(&self, msg: &str) {
        if self.quiet {
            return;
        }
        println!("{msg}");
    }

    /// Shows a command about to be executed
    pub fn command(&self, cmd: &str) {
        if self.quiet || self.json {
            return;
        }
        println!("{}", format!("$ {cmd}").bright_magenta().bold());
    }

    #[allow(dead_code)]
    pub const fn is_quiet(&self) -> bool {
        self.quiet
    }

    #[allow(dead_code)]
    pub const fn is_json(&self) -> bool {
        self.json
    }
}

/// Shows summary line for staged files.
fn show_staged_summary(summary: &Summary, output: &Output) {
    if summary.files_staged == 0 {
        return;
    }
    output.success(&format!("  Staged {} file(s)", summary.files_staged));
}

/// Shows summary line for commits.
fn show_commits_summary(summary: &Summary, output: &Output) {
    if summary.commits_created == 0 {
        return;
    }
    output.success(&format!(
        "  Committed {} commit(s)",
        summary.commits_created
    ));
}

/// Shows summary line for pulled commits.
fn show_pulled_summary(summary: &Summary, output: &Output) {
    if summary.commits_pulled == 0 {
        return;
    }
    output.success(&format!("  Pulled {} commit(s)", summary.commits_pulled));
}

/// Shows summary line for push status.
fn show_push_summary(summary: &Summary, output: &Output) {
    if !summary.pushed {
        return;
    }
    output.success("  Pushed successfully");
}

/// Shows summary line for stash status.
fn show_stash_summary(summary: &Summary, output: &Output) {
    if !summary.stashed {
        return;
    }
    output.info("  Stashed and restored changes");
}

/// Shows summary line for skipped operations.
fn show_skipped_summary(summary: &Summary, output: &Output) {
    if summary.skipped_stage {
        output.warning("  Skipped staging (no changes)");
    }

    if summary.skipped_commit {
        output.warning("  Skipped commit (nothing to commit)");
    }

    if summary.skipped_pull {
        output.warning("  Skipped pull (already up to date)");
    }

    if summary.skipped_push {
        output.warning("  Skipped push (nothing to push)");
    }
}

/// Outputs summary in JSON format.
fn output_json_summary(summary: &Summary) {
    println!(
        r#"{{"files_staged":{},"commits_created":{},"commits_pulled":{},"pushed":{},"stashed":{},"skipped":{{"stage":{},"commit":{},"pull":{},"push":{}}}}}"#,
        summary.files_staged,
        summary.commits_created,
        summary.commits_pulled,
        summary.pushed,
        summary.stashed,
        summary.skipped_stage,
        summary.skipped_commit,
        summary.skipped_pull,
        summary.skipped_push
    );
}

/// Shows a summary of operations performed.
pub fn show_summary(summary: &Summary, output: &Output) {
    if output.quiet {
        return;
    }

    if output.json {
        output_json_summary(summary);
        return;
    }

    output.println("\nSummary:");
    show_staged_summary(summary, output);
    show_commits_summary(summary, output);
    show_pulled_summary(summary, output);
    show_push_summary(summary, output);
    show_stash_summary(summary, output);
    show_skipped_summary(summary, output);
}