extern crate difference;

use ansi_term::Colour::{Green, Red};
use ansi_term::Style;
use difference::{Changeset, Difference};
use std::env;

pub fn print_diff(cs: &Changeset) -> std::io::Result<()> {
    let Changeset { diffs, .. } = cs;

    let red_fg;
    let green_fg;

    match env::var("TERM").as_ref().map(String::as_str) {
        Ok("dumb") | Err(_) => {
            red_fg = Style::new();
            green_fg = Style::new();
        }
        Ok(_) => {
            red_fg = Style::new().fg(Red);
            green_fg = Style::new().fg(Green);
        }
    }

    for diff in diffs {
        match diff {
            Difference::Same(x) => {
                for line in x.lines() {
                    println!(" {}", line);
                }
            }
            Difference::Add(x) => {
                for line in x.lines() {
                    println!("{}{}", green_fg.paint("+"), green_fg.paint(line));
                }
            }
            Difference::Rem(x) => {
                for line in x.lines() {
                    println!("{}{}", red_fg.paint("-"), red_fg.paint(line));
                }
            }
        }
    }
    Ok(())
}

#[macro_export]
macro_rules! assert_diff {
    ($orig:expr, $edit:expr) => {{ assert_diff!($orig, $edit, "\n", 0) }};

    ($orig:expr, $edit:expr, $split:expr, $expected:expr) => {{
        let orig = $orig;
        let edit = $edit;

        let changeset = difference::Changeset::new(orig, edit, &($split));
        if changeset.distance != $expected {
            if let Err(e) = $crate::diff::print_diff(&changeset) {
                eprintln!("{}", e);
            }
            panic!(
                "assertion failed: edit distance was {}, not {}, see diff above",
                changeset.distance,
                &($expected)
            )
        }
    }};
}
