use std::rc::Rc;

use super::{Environment, Node, NodeEnum, Precedence, empty::Empty};

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Assign {
    left: Rc<NodeEnum>,
    right: Rc<NodeEnum>,
}

impl Node for Assign {
    fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
        if let NodeEnum::Symbol(symbol) = self.left.as_ref() {
            env.insert(symbol.get_value(), self.right.clone());
            Ok(Empty::EMPTY.clone())
        } else {
            Err(format!(
                "Cannot assign to a {}",
                self.left.as_string(Some(env))
            ))
        }
    }

    fn as_string(&self, env: Option<&Environment>) -> String {
        format!(
            "{} := {}",
            self.left.as_string(env),
            self.right.as_string(env)
        )
    }

    fn precedence(&self) -> Precedence {
        Precedence::Assign
    }
}

impl Assign {
    pub fn get_left(&self) -> Rc<NodeEnum> {
        self.left.clone()
    }

    pub fn get_right(&self) -> Rc<NodeEnum> {
        self.left.clone()
    }
}
