use crate::{
    error::Error,
    interpreter::{memory::Memory, pointer::Pointer, Interpreter},
    macro_parser::check_macro,
};
use quote::ToTokens;

impl<'ast> Interpreter<'ast> {
    pub fn run_macro(&mut self, expr: &'ast syn::Macro) -> Result<Pointer, Error> {
        let s = check_macro(expr)?;
        let Some(&args) = self.parsed_macros.get(expr) else {
            return Err(Error::new_spanned(expr, "Macro has not been parsed ???"));
        };
        let string_idx = match s.as_str() {
            "print" | "println" | "eprint" | "eprintln" | "arcis_static_panic" => 0,
            "assert" | "debug_assert" => 1,
            "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" => 2,
            _ => usize::MAX,
        };
        let mut result_types = Vec::new();
        for (i, arg) in args.iter().enumerate() {
            if i == string_idx {
                continue;
            }
            let (res, layer) = self.run_with_memory_layer(|interpreter| interpreter.run_expr(arg));
            let ptr = res?;
            result_types.push(self.memory.pointed_type(ptr));
            if !layer.is_empty() {
                return Err(Error::new_spanned(
                    arg,
                    format!("Side effects are not allowed in macro `{}!`.", s),
                ));
            }
        }
        // remove false for debugging
        #[allow(clippy::overly_complex_bool_expr)]
        if string_idx == 0 && !args.is_empty() && false {
            println!("{}:", args[0].to_token_stream(),);
            for ty in result_types {
                println!("  {}", ty);
            }
        }
        if s.as_str() == "arcis_static_panic" {
            return Err(Error::new_spanned(
                expr,
                format!(
                    "`arcis_static_panic` has been triggered: {}.",
                    args[0].to_token_stream()
                ),
            ));
        }

        Ok(Memory::SIMPLE_ADDRESS_OF_UNIT.as_pointer())
    }
}
