use super::util::{current_dir, display};
use koala_artifact::{
    run_and_record, verify, RecordOptions, ReviewerKind, VerifyOptions, VerifyStatus,
};
use std::path::PathBuf;
use std::process::ExitCode;

pub fn record(
    kind_str: &str,
    name: &str,
    round: u32,
    reviewer: Option<String>,
    root: Option<PathBuf>,
    command: Vec<String>,
) -> ExitCode {
    let kind: ReviewerKind = match kind_str.parse() {
        Ok(k) => k,
        Err(e) => {
            eprintln!("error: {e}");
            return ExitCode::from(2);
        }
    };
    if command.is_empty() {
        eprintln!("error: missing command — pass it after `--`");
        eprintln!("hint : koala-core artifact record concept --name foo -- grep -rn x crates/");
        return ExitCode::from(2);
    }
    let root = root.unwrap_or_else(current_dir);
    let reviewer = reviewer.unwrap_or_else(|| {
        let user = std::env::var("USER").unwrap_or_else(|_| "anon".into());
        format!("local:{user}")
    });
    let opts = RecordOptions {
        repo_root: root,
        round,
        kind,
        name: name.to_string(),
        reviewer,
    };
    match run_and_record(&opts, &command) {
        Ok(s) => {
            println!("Recording artifact {} ...", display(&s.artifact_path));
            println!("  Command:    {}", command.join(" "));
            println!("  Exit code:  {}", s.exit_code);
            println!("  Output bytes: {}", s.output_bytes);
            println!("  Wall time:  {:.2}s", s.wall_time.as_secs_f64());
            println!("  Hash:       {}", s.hash);
            println!();
            println!("Artifact written. Stage with:");
            println!("  git add {}", display(&s.artifact_path));
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("error: {e}");
            ExitCode::from(1)
        }
    }
}

pub fn verify_cmd(root: Option<PathBuf>, sample: u32, seed: Option<String>) -> ExitCode {
    let root = root.unwrap_or_else(current_dir);
    let opts = VerifyOptions {
        repo_root: root,
        sample_ratio_percent: sample,
        seed: seed.unwrap_or_else(|| "koala-artifact-default".into()),
        diff_lines: 5,
    };
    let report = match verify(&opts) {
        Ok(r) => r,
        Err(e) => {
            eprintln!("error: {e}");
            return ExitCode::from(2);
        }
    };

    if report.total == 0 {
        println!("verify: no artifacts under .review/round-*/");
        return ExitCode::SUCCESS;
    }

    println!(
        "Selected {} of {} artifacts ({}% sample).",
        report.sampled, report.total, sample
    );
    for o in &report.results {
        match &o.status {
            VerifyStatus::Match { hash } => {
                println!("  ✓ match  {}  {hash}", display(&o.artifact));
            }
            VerifyStatus::Mismatch {
                expected,
                actual,
                diff,
            } => {
                println!("  ✗ TAMPERED  {}", display(&o.artifact));
                println!("      expected hash: {expected}");
                println!("      actual hash:   {actual}");
                if !diff.is_empty() {
                    println!("      diff (first {} lines):", diff.len());
                    for line in diff {
                        println!("        {} {}", line.side.marker(), line.text);
                    }
                }
            }
            VerifyStatus::Error(e) => {
                println!("  ! error  {}  {e}", display(&o.artifact));
            }
        }
    }
    println!(
        "\nsummary: {pass} match, {fail} tampered, {err} error (of {sampled} sampled / {total} total)",
        pass = report.pass_count(),
        fail = report.mismatch_count(),
        err = report.error_count(),
        sampled = report.sampled,
        total = report.total,
    );

    if report.is_clean() {
        ExitCode::SUCCESS
    } else {
        ExitCode::from(1)
    }
}
