use itertools::Itertools;

use crate::arg;
use crate::assembler;

#[derive(Debug, Clone)]
pub enum Node {
    Comment(String),
    Label(String),
    Call { name: String, arg: Option<arg::Arg> },
    MacroCall { name: String, args: Vec<arg::Arg> },
}

impl assembler::ToCode for Node {
    fn to_code(&self) -> String {
        match self {
            Node::Comment(x) => format!("; {x}"),
            Node::Label(x) => format!("{x}:"),
            Node::Call { name, arg } => {
                if let Some(a) = arg {
                    format!("{name} {arg}", arg = a.to_code())
                } else {
                    name.clone()
                }
            }
            Node::MacroCall { name, args } => {
                if args.is_empty() {
                    format!(".{name}")
                } else {
                    format!(".{name} {}", args.iter().map(|a| a.to_code()).join(", "))
                }
            }
        }
    }
}

pub type Body = Vec<Node>;

#[derive(Debug, Clone)]
pub struct AST {
    pub body: Vec<Node>,
}

impl assembler::ToCode for AST {
    fn to_code(&self) -> String {
        self.body.iter().map(|n| n.to_code()).join("\n")
    }
}
