pub struct Node {
    pub name: String,
    pub kind: NodeKind,
}
#[derive(Clone)]
pub enum NodeKind {
    Enum { variants: Vec<Variant>, missing_variant: Option<Variant> },
    Struct { members: Vec<Member> },
    Terminal { is_keyword: bool, members: Vec<Member> },
    List { element_type: String },
    SeparatedList { element_type: String, separator_type: String },
    Token { is_keyword: bool },
}
#[derive(Clone)]
pub struct Member {
    pub name: String,
    pub kind: String,
    pub key: bool,
}
#[derive(Clone)]
pub struct Variant {
    pub name: String,
    pub kind: String,
}
pub struct StructBuilder {
    name: String,
    members: Vec<Member>,
    is_terminal: bool,
    is_keyword: bool,
}
impl StructBuilder {
    pub fn new(name: &str) -> Self {
        Self { name: name.into(), members: Vec::new(), is_terminal: false, is_keyword: false }
    }
    pub fn new_terminal(name: &str, is_keyword: bool) -> Self {
        Self { name: name.into(), members: Vec::new(), is_terminal: true, is_keyword }
    }
    pub fn node(mut self, field: &str, kind: &str) -> StructBuilder {
        self.members.push(Member { name: field.into(), kind: kind.into(), key: false });
        self
    }
    pub fn key_node(mut self, field: &str, kind: &str) -> StructBuilder {
        self.members.push(Member { name: field.into(), kind: kind.into(), key: true });
        self
    }
    pub fn build(self) -> Node {
        Node {
            name: self.name,
            kind: if self.is_terminal {
                NodeKind::Terminal { is_keyword: self.is_keyword, members: self.members }
            } else {
                NodeKind::Struct { members: self.members }
            },
        }
    }
}
pub struct EnumBuilder {
    name: String,
    variants: Vec<Variant>,
    missing_variant: Option<Variant>,
}
impl EnumBuilder {
    pub fn new(name: &str) -> Self {
        Self { name: name.into(), variants: Vec::new(), missing_variant: None }
    }
    pub fn missing(mut self, name: &str) -> EnumBuilder {
        let kind_name = self.name.clone() + name;
        self.missing_variant = Some(Variant { name: name.to_string(), kind: kind_name });
        self
    }
    pub fn node(self, name: &str) -> EnumBuilder {
        let kind_name = self.name.clone() + name;
        self.node_with_explicit_kind(name, &kind_name)
    }
    pub fn node_with_explicit_kind(mut self, name: &str, kind: &str) -> EnumBuilder {
        self.variants.push(Variant { name: name.to_string(), kind: kind.to_string() });
        self
    }
    pub fn build(mut self) -> Node {
        if let Some(member) = &self.missing_variant {
            self.variants.push(member.clone());
        }
        Node {
            name: self.name,
            kind: NodeKind::Enum { variants: self.variants, missing_variant: self.missing_variant },
        }
    }
}
#[derive(Default)]
pub struct NodesAggregator {
    nodes: Vec<Node>,
}
impl NodesAggregator {
    pub fn get(self) -> Vec<Node> {
        self.nodes
    }
    pub fn add_struct(mut self, builder: StructBuilder) -> Self {
        self.nodes.push(builder.build());
        self
    }
    pub fn add_enum(mut self, builder: EnumBuilder) -> Self {
        self.nodes.push(builder.build());
        self
    }
    pub fn add_list(mut self, name: &str, element_type: &str) -> Self {
        self.nodes.push(Node {
            name: name.into(),
            kind: NodeKind::List { element_type: element_type.into() },
        });
        self
    }
    pub fn add_separated_list(
        mut self,
        name: &str,
        element_type: &str,
        separator_type: &str,
    ) -> Self {
        self.nodes.push(Node {
            name: name.into(),
            kind: NodeKind::SeparatedList {
                element_type: element_type.into(),
                separator_type: separator_type.into(),
            },
        });
        self
    }
    pub fn add_token(mut self, pure_name: &str) -> Self {
        self.nodes.push(Node {
            name: format!("Token{pure_name}"),
            kind: NodeKind::Token { is_keyword: false },
        });
        self
    }
    pub fn add_keyword_token(mut self, pure_name: &str) -> Self {
        self.nodes.push(Node {
            name: format!("Token{pure_name}"),
            kind: NodeKind::Token { is_keyword: true },
        });
        self
    }
    pub fn add_terminal(self, pure_name: &str, is_keyword: bool) -> Self {
        self.add_struct(
            StructBuilder::new_terminal(format!("Terminal{pure_name}").as_str(), is_keyword)
                .node("leading_trivia", "Trivia")
                .node("token", format!("Token{pure_name}").as_str())
                .node("trailing_trivia", "Trivia"),
        )
    }
    pub fn add_keyword_token_and_terminal(self, pure_name: &str) -> Self {
        self.add_keyword_token(pure_name).add_terminal(pure_name, true)
    }
    pub fn add_token_and_terminal(self, pure_name: &str) -> Self {
        self.add_token(pure_name).add_terminal(pure_name, false)
    }
    pub fn add_option(self, name: &str) -> Self {
        self.add_enum(
            EnumBuilder::new(format!("Option{name}").as_str())
                .node("Empty")
                .node_with_explicit_kind(name, name),
        )
        .add_struct(StructBuilder::new(format!("Option{name}Empty").as_str()))
    }
}