use crate::context::Context;

use crate::parser::{parse, ErrorAt};
use crate::scope::Scope;
use crate::tokenizer::tokenize;

pub fn run(code: &str) -> Result<Vec<String>, ErrorAt> {
    let tokens = tokenize(code)?;
    let commands = parse(tokens)?;
    let mut scope = Scope::new();
    scope.commands = commands.into();
    let mut context = Context::default();
    let res = context.evaluate(&mut scope);
    res.map_err(|e| (e, context.last_command.unwrap().start))
}

#[cfg(test)]
mod tests {
    use crate::run::run;

    #[test]
    fn or() {
        assert_eq!(run("1 or 2").unwrap(), vec!["1"]);
    }

    #[test]
    fn number() {
        assert_eq!(run("1").unwrap(), vec!["1"]);
    }

    #[test]
    fn simple_function() {
        assert_eq!(run("a(b):b a 5").unwrap(), vec!["5"]);
    }

    #[test]
    fn seperate() {
        assert_eq!(
            run("0 0 10 0 0 20 30 0 0 40 seperated-by (0 0) (sum)").unwrap(),
            vec!["10", "50", "40"]
        );
    }

    #[test]
    fn comment() {
        assert_eq!(run("# a(b):b a 5").unwrap(), Vec::<String>::new());
    }

    #[test]
    fn error() {
        assert_eq!(run("error 'message"), Err(("message".to_string(), (1, 7))));
    }

    #[test]
    fn expected_parameter() {
        assert_eq!(
            run("on-error 'message"),
            Err((
                "Expected parameter then for built-in on-error".to_string(),
                (1, 7)
            ))
        );
    }

    #[test]
    fn unclosed_string() {
        assert_eq!(run("\""), Err(("Unfinished String".to_string(), (1, 7))));
    }

    #[test]
    fn unexpected_closing() {
        assert_eq!(
            run("(()()))"),
            Err(("Unexpected closing parenthesis".to_string(), (1, 7)))
        );
    }

    #[test]
    fn open_close() {
        assert_eq!(run("()").unwrap(), Vec::<String>::new());
    }

    #[test]
    fn catch_error() {
        assert_eq!(
            run("on-error 'mes (error 'message) ()").unwrap(),
            Vec::<String>::new()
        );
    }
}