use crate::{
    parser::ast::{NumNode, PartNode, StrongNode, WeakNode, WordNode},
    CyberWaifuTags,
};
use std::str::FromStr;

use self::ast::PromptNode;
#[allow(unused, non_camel_case_types)]
pub(crate) mod ast;

impl PromptNode {
    pub(crate) fn visit(self, cw: &mut CyberWaifuTags) {
        for part in self.part {
            part.visit(cw, 0.0)
        }
    }
}

impl PartNode {
    fn visit(self, cw: &mut CyberWaifuTags, depth: f32) {
        match self {
            PartNode::NumNode(e) => e.visit(cw, depth),
            PartNode::StrongNode(e) => e.visit(cw, depth),
            PartNode::TotalNode(_) => {
                unimplemented!()
            }
            PartNode::WeakNode(e) => e.visit(cw, depth),
            PartNode::WordNode(e) => e.visit(cw, depth),
        }
    }
}

impl WordNode {
    fn visit(self, cw: &mut CyberWaifuTags, depth: f32) {
        cw.push_tag(self.as_str(), depth);
    }
    fn as_str(&self) -> String {
        let v: Vec<_> = self.id.iter().map(|f| f.string.to_string()).collect();
        v.join(" ")
    }
}

impl StrongNode {
    fn visit(self, cw: &mut CyberWaifuTags, depth: f32) {
        let level = match self.num {
            Some(s) => s.as_f32(),
            None => 1.0,
        };
        for part in self.parts {
            part.visit(cw, depth + level)
        }
    }
}

impl WeakNode {
    fn visit(self, cw: &mut CyberWaifuTags, depth: f32) {
        let level = match self.num {
            Some(s) => s.as_f32(),
            None => 1.0,
        };
        for part in self.parts {
            part.visit(cw, depth - level)
        }
    }
}

impl NumNode {
    fn visit(self, _: &mut CyberWaifuTags, _: f32) {
        // do nothing
    }
    pub fn as_f32(&self) -> f32 {
        f32::from_str(&self.string).unwrap_or(1.0)
    }
}
