use std::collections::HashMap;
use crate::dna::atp::value::Value;
use crate::dna::atp::types::{TimeUnit, Duration, SecretRef};
#[derive(Debug, Clone)]
pub struct SectionDecl {
    pub name: String,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct HelixAst {
    pub declarations: Vec<Declaration>,
}
#[derive(Debug, Clone)]
pub enum Declaration {
    Project(ProjectDecl),
    Agent(AgentDecl),
    Workflow(WorkflowDecl),
    Memory(MemoryDecl),
    Context(ContextDecl),
    Crew(CrewDecl),
    Pipeline(PipelineDecl),
    Plugin(PluginDecl),
    Database(DatabaseDecl),
    Task(TaskDecl),
    Load(LoadDecl),
    Section(SectionDecl),
}
#[derive(Debug, Clone)]
pub struct ProjectDecl {
    pub name: String,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct AgentDecl {
    pub name: String,
    pub properties: HashMap<String, Expression>,
    pub capabilities: Option<Vec<String>>,
    pub backstory: Option<BackstoryBlock>,
    pub tools: Option<Vec<String>>,
}
#[derive(Debug, Clone)]
pub struct WorkflowDecl {
    pub name: String,
    pub trigger: Option<Expression>,
    pub steps: Vec<StepDecl>,
    pub pipeline: Option<PipelineDecl>,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct StepDecl {
    pub name: String,
    pub agent: Option<String>,
    pub crew: Option<Vec<String>>,
    pub task: Option<String>,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct PipelineDecl {
    pub flow: Vec<PipelineNode>,
}
#[derive(Debug, Clone)]
pub enum PipelineNode {
    Step(String),
    Parallel(Vec<PipelineNode>),
    Conditional {
        condition: Expression,
        then_branch: Box<PipelineNode>,
        else_branch: Option<Box<PipelineNode>>,
    },
}
#[derive(Debug, Clone)]
pub struct MemoryDecl {
    pub provider: String,
    pub connection: String,
    pub embeddings: Option<EmbeddingsDecl>,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct EmbeddingsDecl {
    pub model: String,
    pub dimensions: u32,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct ContextDecl {
    pub name: String,
    pub environment: String,
    pub secrets: Option<HashMap<String, SecretRef>>,
    pub variables: Option<HashMap<String, Expression>>,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct CrewDecl {
    pub name: String,
    pub agents: Vec<String>,
    pub process_type: Option<String>,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct PluginDecl {
    pub name: String,
    pub source: String,
    pub version: Option<String>,
    pub config: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct DatabaseDecl {
    pub name: String,
    pub path: Option<String>,
    pub shards: Option<i64>,
    pub compression: Option<bool>,
    pub cache_size: Option<i64>,
    pub vector_index: Option<VectorIndexConfig>,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct TaskDecl {
    pub name: String,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct VectorIndexConfig {
    pub index_type: String,
    pub dimensions: i64,
    pub m: Option<i64>,
    pub ef_construction: Option<i64>,
    pub distance_metric: Option<String>,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct LoadDecl {
    pub file_name: String,
    pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone)]
pub struct BackstoryBlock {
    pub lines: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOperator {
    Eq,
    Ne,
    Lt,
    Le,
    Gt,
    Ge,
    And,
    Or,
    Add,
    Sub,
    Mul,
    Div,
}
#[derive(Debug, Clone)]
pub enum Expression {
    String(String),
    Number(f64),
    Bool(bool),
    Null,
    Duration(Duration),
    Array(Vec<Expression>),
    Object(HashMap<String, Expression>),
    Variable(String),
    Reference(String),
    IndexedReference(String, String),
    Identifier(String),
    Pipeline(Vec<String>),
    BinaryOp(Box<Expression>, BinaryOperator, Box<Expression>),
    Block(Vec<Statement>),
    TextBlock(Vec<String>),
    OperatorCall(String, String, Option<String>, Option<String>),
    AtOperatorCall(String, HashMap<String, Expression>),
}
#[derive(Debug, Clone)]
pub enum Statement {
    Assignment(String, Expression),
    Declaration(Declaration),
    Expression(Expression),
}
impl HelixAst {
    pub fn new() -> Self {
        HelixAst {
            declarations: Vec::new(),
        }
    }
    pub fn add_declaration(&mut self, decl: Declaration) {
        self.declarations.push(decl);
    }
    pub fn get_projects(&self) -> Vec<&ProjectDecl> {
        self.declarations
            .iter()
            .filter_map(|d| {
                if let Declaration::Project(p) = d { Some(p) } else { None }
            })
            .collect()
    }
    pub fn get_agents(&self) -> Vec<&AgentDecl> {
        self.declarations
            .iter()
            .filter_map(|d| {
                if let Declaration::Agent(a) = d { Some(a) } else { None }
            })
            .collect()
    }
    pub fn get_workflows(&self) -> Vec<&WorkflowDecl> {
        self.declarations
            .iter()
            .filter_map(|d| {
                if let Declaration::Workflow(w) = d { Some(w) } else { None }
            })
            .collect()
    }
    pub fn get_contexts(&self) -> Vec<&ContextDecl> {
        self.declarations
            .iter()
            .filter_map(|d| {
                if let Declaration::Context(c) = d { Some(c) } else { None }
            })
            .collect()
    }
}
#[allow(dead_code)]
pub trait AstVisitor {
    type Result;
    fn visit_ast(&mut self, ast: &HelixAst) -> Self::Result;
    fn visit_declaration(&mut self, decl: &Declaration) -> Self::Result;
    fn visit_project(&mut self, project: &ProjectDecl) -> Self::Result;
    fn visit_agent(&mut self, agent: &AgentDecl) -> Self::Result;
    fn visit_workflow(&mut self, workflow: &WorkflowDecl) -> Self::Result;
    fn visit_memory(&mut self, memory: &MemoryDecl) -> Self::Result;
    fn visit_context(&mut self, context: &ContextDecl) -> Self::Result;
    fn visit_crew(&mut self, crew: &CrewDecl) -> Self::Result;
    fn visit_section(&mut self, section: &SectionDecl) -> Self::Result;
    fn visit_expression(&mut self, expr: &Expression) -> Self::Result;
}
pub struct AstPrettyPrinter {
    indent: usize,
    indent_str: String,
}
impl AstPrettyPrinter {
    pub fn new() -> Self {
        AstPrettyPrinter {
            indent: 0,
            indent_str: "  ".to_string(),
        }
    }
    fn write_indent(&self) -> String {
        self.indent_str.repeat(self.indent)
    }
    pub fn print(&mut self, ast: &HelixAst) -> String {
        let mut result = String::new();
        result.push_str("# HELIX Language AST\n\n");
        for decl in &ast.declarations {
            result.push_str(&self.print_declaration(decl));
            result.push_str("\n");
        }
        result
    }
    fn print_declaration(&mut self, decl: &Declaration) -> String {
        match decl {
            Declaration::Project(p) => self.print_project(p),
            Declaration::Agent(a) => self.print_agent(a),
            Declaration::Workflow(w) => self.print_workflow(w),
            Declaration::Memory(m) => self.print_memory(m),
            Declaration::Context(c) => self.print_context(c),
            Declaration::Crew(cr) => self.print_crew(cr),
            Declaration::Pipeline(p) => self.print_pipeline(p),
            Declaration::Plugin(p) => self.print_plugin(p),
            Declaration::Database(d) => self.print_database(d),
            Declaration::Task(t) => self.print_task(t),
            Declaration::Load(l) => self.print_load(l),
            Declaration::Section(s) => self.print_section(s),
        }
    }
    fn print_project(&mut self, project: &ProjectDecl) -> String {
        let mut result = format!(
            "{}project \"{}\" {{\n", self.write_indent(), project.name
        );
        self.indent += 1;
        let mut keys: Vec<_> = project.properties.keys().collect();
        keys.sort();
        for key in keys {
            let value = &project.properties[key];
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_agent(&mut self, agent: &AgentDecl) -> String {
        let mut result = format!("{}agent \"{}\" {{\n", self.write_indent(), agent.name);
        self.indent += 1;
        let mut keys: Vec<_> = agent.properties.keys().collect();
        keys.sort();
        for key in keys {
            let value = &agent.properties[key];
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        if let Some(capabilities) = &agent.capabilities {
            result.push_str(&format!("{}capabilities [\n", self.write_indent()));
            self.indent += 1;
            for cap in capabilities {
                result.push_str(&format!("{}\"{}\"\n", self.write_indent(), cap));
            }
            self.indent -= 1;
            result.push_str(&format!("{}]\n", self.write_indent()));
        }
        if let Some(backstory) = &agent.backstory {
            result.push_str(&format!("{}backstory {{\n", self.write_indent()));
            self.indent += 1;
            for line in &backstory.lines {
                result.push_str(&format!("{}{}\n", self.write_indent(), line));
            }
            self.indent -= 1;
            result.push_str(&format!("{}}}\n", self.write_indent()));
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_workflow(&mut self, workflow: &WorkflowDecl) -> String {
        let mut result = format!(
            "{}workflow \"{}\" {{\n", self.write_indent(), workflow.name
        );
        self.indent += 1;
        if let Some(trigger) = &workflow.trigger {
            result
                .push_str(
                    &format!(
                        "{}trigger = {}\n", self.write_indent(), self
                        .print_expression(trigger)
                    ),
                );
        }
        for step in &workflow.steps {
            result.push_str(&self.print_step(step));
        }
        if let Some(pipeline) = &workflow.pipeline {
            result.push_str(&self.print_pipeline(pipeline));
        }
        for (key, value) in &workflow.properties {
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_step(&mut self, step: &StepDecl) -> String {
        let mut result = format!("{}step \"{}\" {{\n", self.write_indent(), step.name);
        self.indent += 1;
        if let Some(agent) = &step.agent {
            result.push_str(&format!("{}agent = \"{}\"\n", self.write_indent(), agent));
        }
        if let Some(crew) = &step.crew {
            result.push_str(&format!("{}crew = [", self.write_indent()));
            result
                .push_str(
                    &crew
                        .iter()
                        .map(|c| format!("\"{}\"", c))
                        .collect::<Vec<_>>()
                        .join(", "),
                );
            result.push_str("]\n");
        }
        if let Some(task) = &step.task {
            result.push_str(&format!("{}task = \"{}\"\n", self.write_indent(), task));
        }
        for (key, value) in &step.properties {
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_memory(&mut self, memory: &MemoryDecl) -> String {
        let mut result = format!("{}memory {{\n", self.write_indent());
        self.indent += 1;
        result
            .push_str(
                &format!("{}provider = \"{}\"\n", self.write_indent(), memory.provider),
            );
        result
            .push_str(
                &format!(
                    "{}connection = \"{}\"\n", self.write_indent(), memory.connection
                ),
            );
        if let Some(embeddings) = &memory.embeddings {
            result.push_str(&self.print_embeddings(embeddings));
        }
        for (key, value) in &memory.properties {
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_embeddings(&mut self, embeddings: &EmbeddingsDecl) -> String {
        let mut result = format!("{}embeddings {{\n", self.write_indent());
        self.indent += 1;
        result
            .push_str(
                &format!("{}model = \"{}\"\n", self.write_indent(), embeddings.model),
            );
        result
            .push_str(
                &format!(
                    "{}dimensions = {}\n", self.write_indent(), embeddings.dimensions
                ),
            );
        for (key, value) in &embeddings.properties {
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_context(&mut self, context: &ContextDecl) -> String {
        let mut result = format!(
            "{}context \"{}\" {{\n", self.write_indent(), context.name
        );
        self.indent += 1;
        result
            .push_str(
                &format!(
                    "{}environment = \"{}\"\n", self.write_indent(), context.environment
                ),
            );
        if let Some(secrets) = &context.secrets {
            result.push_str(&format!("{}secrets {{\n", self.write_indent()));
            self.indent += 1;
            let mut keys: Vec<_> = secrets.keys().collect();
            keys.sort();
            for key in keys {
                let secret_ref = &secrets[key];
                result
                    .push_str(
                        &format!(
                            "{}{} = {}\n", self.write_indent(), key, self
                            .print_secret_ref(secret_ref)
                        ),
                    );
            }
            self.indent -= 1;
            result.push_str(&format!("{}}}\n", self.write_indent()));
        }
        if let Some(variables) = &context.variables {
            result.push_str(&format!("{}variables {{\n", self.write_indent()));
            self.indent += 1;
            let mut keys: Vec<_> = variables.keys().collect();
            keys.sort();
            for key in keys {
                let value = &variables[key];
                result
                    .push_str(
                        &format!(
                            "{}{} = {}\n", self.write_indent(), key, self
                            .print_expression(value)
                        ),
                    );
            }
            self.indent -= 1;
            result.push_str(&format!("{}}}\n", self.write_indent()));
        }
        let mut keys: Vec<_> = context.properties.keys().collect();
        keys.sort();
        for key in keys {
            let value = &context.properties[key];
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_crew(&mut self, crew: &CrewDecl) -> String {
        let mut result = format!("{}crew \"{}\" {{\n", self.write_indent(), crew.name);
        self.indent += 1;
        result.push_str(&format!("{}agents [\n", self.write_indent()));
        self.indent += 1;
        for agent in &crew.agents {
            result.push_str(&format!("{}\"{}\"\n", self.write_indent(), agent));
        }
        self.indent -= 1;
        result.push_str(&format!("{}]\n", self.write_indent()));
        if let Some(process_type) = &crew.process_type {
            result
                .push_str(
                    &format!("{}process = \"{}\"\n", self.write_indent(), process_type),
                );
        }
        for (key, value) in &crew.properties {
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_plugin(&mut self, plugin: &PluginDecl) -> String {
        let mut result = format!(
            "{}plugin \"{}\" {{\n", self.write_indent(), plugin.name
        );
        self.indent += 1;
        result
            .push_str(
                &format!("{}source = \"{}\"\n", self.write_indent(), plugin.source),
            );
        if let Some(version) = &plugin.version {
            result
                .push_str(
                    &format!("{}version = \"{}\"\n", self.write_indent(), version),
                );
        }
        for (key, value) in &plugin.config {
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_database(&mut self, database: &DatabaseDecl) -> String {
        let mut result = format!(
            "{}database \"{}\" {{\n", self.write_indent(), database.name
        );
        self.indent += 1;
        if let Some(path) = &database.path {
            result.push_str(&format!("{}path = \"{}\"\n", self.write_indent(), path));
        }
        if let Some(shards) = database.shards {
            result.push_str(&format!("{}shards = {}\n", self.write_indent(), shards));
        }
        if let Some(compression) = database.compression {
            result
                .push_str(
                    &format!("{}compression = {}\n", self.write_indent(), compression),
                );
        }
        if let Some(cache_size) = database.cache_size {
            result
                .push_str(
                    &format!("{}cache_size = {}\n", self.write_indent(), cache_size),
                );
        }
        if let Some(vector_index) = &database.vector_index {
            result.push_str(&format!("{}vector_index {{\n", self.write_indent()));
            self.indent += 1;
            result
                .push_str(
                    &format!(
                        "{}index_type = \"{}\"\n", self.write_indent(), vector_index
                        .index_type
                    ),
                );
            result
                .push_str(
                    &format!(
                        "{}dimensions = {}\n", self.write_indent(), vector_index
                        .dimensions
                    ),
                );
            if let Some(m) = vector_index.m {
                result.push_str(&format!("{}m = {}\n", self.write_indent(), m));
            }
            if let Some(ef_construction) = vector_index.ef_construction {
                result
                    .push_str(
                        &format!(
                            "{}ef_construction = {}\n", self.write_indent(),
                            ef_construction
                        ),
                    );
            }
            if let Some(distance_metric) = &vector_index.distance_metric {
                result
                    .push_str(
                        &format!(
                            "{}distance_metric = \"{}\"\n", self.write_indent(),
                            distance_metric
                        ),
                    );
            }
            self.indent -= 1;
            result.push_str(&format!("{}}}\n", self.write_indent()));
        }
        for (key, value) in &database.properties {
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_task(&mut self, task: &TaskDecl) -> String {
        let mut result = format!(
            "{}task \"{}\" {{\n", self.write_indent(), task.name
        );
        self.indent += 1;
        let mut keys: Vec<_> = task.properties.keys().collect();
        keys.sort();
        for key in keys {
            let value = &task.properties[key];
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_load(&mut self, load: &LoadDecl) -> String {
        let mut result = format!(
            "{}load \"{}\" {{\n", self.write_indent(), load.file_name
        );
        self.indent += 1;
        for (key, value) in &load.properties {
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_section(&mut self, section: &SectionDecl) -> String {
        let mut result = format!("{}section {} {{\n", self.write_indent(), section.name);
        self.indent += 1;
        let mut keys: Vec<_> = section.properties.keys().collect();
        keys.sort();
        for key in keys {
            let value = &section.properties[key];
            result
                .push_str(
                    &format!(
                        "{}{} = {}\n", self.write_indent(), key, self
                        .print_expression(value)
                    ),
                );
        }
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_pipeline(&mut self, pipeline: &PipelineDecl) -> String {
        let mut result = format!("{}pipeline {{\n", self.write_indent());
        self.indent += 1;
        let flow_str = pipeline
            .flow
            .iter()
            .map(|node| match node {
                PipelineNode::Step(s) => s.clone(),
                _ => "...".to_string(),
            })
            .collect::<Vec<_>>()
            .join(" -> ");
        result.push_str(&format!("{}{}\n", self.write_indent(), flow_str));
        self.indent -= 1;
        result.push_str(&format!("{}}}\n", self.write_indent()));
        result
    }
    fn print_secret_ref(&mut self, secret_ref: &SecretRef) -> String {
        match secret_ref {
            SecretRef::Environment(var) => format!("${}", var),
            SecretRef::Vault(path) => format!("vault:\"{}\"", path),
            SecretRef::File(path) => format!("file:\"{}\"", path),
        }
    }
    fn print_expression(&mut self, expr: &Expression) -> String {
        match expr {
            Expression::String(s) => format!("\"{}\"", s),
            Expression::Number(n) => format!("{}", n),
            Expression::Bool(b) => format!("{}", b),
            Expression::Duration(d) => {
                format!(
                    "{}{}", d.value, match d.unit { TimeUnit::Seconds => "s",
                    TimeUnit::Minutes => "m", TimeUnit::Hours => "h", TimeUnit::Days =>
                    "d", }
                )
            }
            Expression::Variable(v) => format!("${}", v),
            Expression::Reference(r) => format!("@{}", r),
            Expression::IndexedReference(file, key) => format!("@{}[{}]", file, key),
            Expression::Identifier(i) => i.clone(),
            Expression::Pipeline(stages) => stages.join(" -> "),
            Expression::Array(items) => {
                format!(
                    "[{}]", items.iter().map(| i | self.print_expression(i)).collect::<
                    Vec < _ >> ().join(", ")
                )
            }
            Expression::Object(map) => {
                let mut keys: Vec<_> = map.keys().collect();
                keys.sort();
                let items = keys
                    .into_iter()
                    .map(|k| format!("{} = {}", k, self.print_expression(& map[k])))
                    .collect::<Vec<_>>()
                    .join(", ");
                format!("{{ {} }}", items)
            }
            Expression::Null => "null".to_string(),
            Expression::BinaryOp(left, op, right) => {
                let op_str = match op {
                    BinaryOperator::Eq => "==",
                    BinaryOperator::Ne => "!=",
                    BinaryOperator::Lt => "<",
                    BinaryOperator::Le => "<=",
                    BinaryOperator::Gt => ">",
                    BinaryOperator::Ge => ">=",
                    BinaryOperator::And => "&&",
                    BinaryOperator::Or => "||",
                    BinaryOperator::Add => "+",
                    BinaryOperator::Sub => "-",
                    BinaryOperator::Mul => "*",
                    BinaryOperator::Div => "/",
                };
                format!(
                    "{} {} {}", self.print_expression(left), op_str, self
                    .print_expression(right)
                )
            }
            _ => "...".to_string(),
        }
    }
}
impl Expression {
    pub fn binary(left: Expression, op: BinaryOperator, right: Expression) -> Self {
        Expression::BinaryOp(Box::new(left), op, Box::new(right))
    }
    pub fn as_string(&self) -> Option<String> {
        match self {
            Expression::String(s) => Some(s.clone()),
            Expression::Identifier(s) => Some(s.clone()),
            _ => None,
        }
    }
    pub fn as_number(&self) -> Option<f64> {
        match self {
            Expression::Number(n) => Some(*n),
            _ => None,
        }
    }
    pub fn as_bool(&self) -> Option<bool> {
        match self {
            Expression::Bool(b) => Some(*b),
            _ => None,
        }
    }
    pub fn as_array(&self) -> Option<Vec<Expression>> {
        match self {
            Expression::Array(arr) => Some(arr.clone()),
            _ => None,
        }
    }
    pub fn as_object(&self) -> Option<&HashMap<String, Expression>> {
        match self {
            Expression::Object(map) => Some(map),
            _ => None,
        }
    }
    pub fn to_value(&self) -> Value {
        match self {
            Expression::String(s) => Value::String(s.clone()),
            Expression::Number(n) => Value::Number(*n),
            Expression::Bool(b) => Value::Bool(*b),
            Expression::Null => Value::Null,
            Expression::Duration(d) => Value::Duration(d.clone()),
            Expression::Array(arr) => {
                Value::Array(arr.iter().map(|e| e.to_value()).collect())
            }
            Expression::Object(map) => {
                Value::Object(
                    map.iter().map(|(k, v)| (k.clone(), v.to_value())).collect(),
                )
            }
            Expression::Variable(v) => Value::Reference(format!("${}", v)),
            Expression::Reference(r) => Value::Reference(format!("@{}", r)),
            Expression::IndexedReference(file, key) => {
                Value::Reference(format!("@{}[{}]", file, key))
            }
            Expression::Identifier(i) => Value::Identifier(i.clone()),
            Expression::BinaryOp(left, op, right) => {
                let op_str = match op {
                    BinaryOperator::Eq => "==",
                    BinaryOperator::Ne => "!=",
                    BinaryOperator::Lt => "<",
                    BinaryOperator::Le => "<=",
                    BinaryOperator::Gt => ">",
                    BinaryOperator::Ge => ">=",
                    BinaryOperator::And => "&&",
                    BinaryOperator::Or => "||",
                    BinaryOperator::Add => "+",
                    BinaryOperator::Sub => "-",
                    BinaryOperator::Mul => "*",
                    BinaryOperator::Div => "/",
                };
                Value::String(
                    format!(
                        "{} {} {}", format!("{:?}", left.to_value()), op_str,
                        format!("{:?}", right.to_value())
                    ),
                )
            }
            _ => Value::String("".to_string()),
        }
    }
}
#[allow(dead_code)]
pub struct AstBuilder {
    ast: HelixAst,
}
#[allow(dead_code)]
impl AstBuilder {
    pub fn new() -> Self {
        AstBuilder { ast: HelixAst::new() }
    }
    pub fn add_project(
        mut self,
        name: String,
        properties: HashMap<String, Expression>,
    ) -> Self {
        self.ast.add_declaration(Declaration::Project(ProjectDecl { name, properties }));
        self
    }
    pub fn add_agent(mut self, agent: AgentDecl) -> Self {
        self.ast.add_declaration(Declaration::Agent(agent));
        self
    }
    pub fn add_workflow(mut self, workflow: WorkflowDecl) -> Self {
        self.ast.add_declaration(Declaration::Workflow(workflow));
        self
    }
    pub fn add_context(mut self, context: ContextDecl) -> Self {
        self.ast.add_declaration(Declaration::Context(context));
        self
    }
    pub fn add_memory(mut self, memory: MemoryDecl) -> Self {
        self.ast.add_declaration(Declaration::Memory(memory));
        self
    }
    pub fn add_crew(mut self, crew: CrewDecl) -> Self {
        self.ast.add_declaration(Declaration::Crew(crew));
        self
    }
    pub fn add_pipeline(mut self, pipeline: PipelineDecl) -> Self {
        self.ast.add_declaration(Declaration::Pipeline(pipeline));
        self
    }
    pub fn add_plugin(mut self, plugin: PluginDecl) -> Self {
        self.ast.add_declaration(Declaration::Plugin(plugin));
        self
    }
    pub fn add_database(mut self, database: DatabaseDecl) -> Self {
        self.ast.add_declaration(Declaration::Database(database));
        self
    }
    pub fn add_load(mut self, load: LoadDecl) -> Self {
        self.ast.add_declaration(Declaration::Load(load));
        self
    }
    pub fn add_section(mut self, section: SectionDecl) -> Self {
        self.ast.add_declaration(Declaration::Section(section));
        self
    }
    pub fn build(self) -> HelixAst {
        self.ast
    }
}
