/// Span in source text for error reporting.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Span {
    pub start: usize,
    pub end: usize,
}

/// Top-level program: a sequence of statements.
#[derive(Debug, Clone)]
pub struct Program {
    pub statements: Vec<Statement>,
}

#[derive(Debug, Clone)]
pub enum Statement {
    /// A module call like `cube([10,20,30]);` or `translate([1,0,0]) cube(5);`
    ModuleCall(ModuleCall),
    /// Boolean operations: `union() { ... }`, `difference() { ... }`, `intersection() { ... }`
    BooleanOp(BooleanOp),
    /// Variable assignment: `x = 10;`
    Assignment(Assignment),
    /// Module definition: `module name(params) { ... }`
    ModuleDef(ModuleDef),
    /// For loop: `for (i = [start:step:end]) { ... }`
    ForLoop(ForLoop),
    /// If/else: `if (cond) { ... } else { ... }`
    IfElse(IfElse),
}

#[derive(Debug, Clone)]
pub struct ModuleCall {
    pub name: String,
    pub args: Vec<Argument>,
    pub children: Vec<Statement>,
    pub span: Span,
}

#[derive(Debug, Clone)]
pub struct BooleanOp {
    pub op: BooleanKind,
    pub children: Vec<Statement>,
    pub span: Span,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BooleanKind {
    Union,
    Difference,
    Intersection,
}

#[derive(Debug, Clone)]
pub struct Assignment {
    pub name: String,
    pub value: Expr,
    pub span: Span,
}

#[derive(Debug, Clone)]
pub struct ModuleDef {
    pub name: String,
    pub params: Vec<Param>,
    pub body: Vec<Statement>,
    pub span: Span,
}

#[derive(Debug, Clone)]
pub struct Param {
    pub name: String,
    pub default: Option<Expr>,
}

#[derive(Debug, Clone)]
pub struct ForLoop {
    pub var: String,
    pub range: ForRange,
    pub body: Vec<Statement>,
    pub span: Span,
}

#[derive(Debug, Clone)]
pub enum ForRange {
    /// [start : end] or [start : step : end]
    Range { start: Expr, step: Option<Expr>, end: Expr },
    /// [a, b, c, ...] — explicit list
    List(Vec<Expr>),
}

#[derive(Debug, Clone)]
pub struct IfElse {
    pub condition: Expr,
    pub then_body: Vec<Statement>,
    pub else_body: Vec<Statement>,
    pub span: Span,
}

#[derive(Debug, Clone)]
pub struct Argument {
    pub name: Option<String>,
    pub value: Expr,
}

#[derive(Debug, Clone)]
pub enum Expr {
    Number(f64),
    Bool(bool),
    String(String),
    Ident(String),
    Vector(Vec<Expr>),
    UnaryOp { op: UnaryOp, operand: Box<Expr> },
    BinaryOp { op: BinaryOp, left: Box<Expr>, right: Box<Expr> },
    FnCall { name: String, args: Vec<Argument> },
    Ternary { cond: Box<Expr>, then_expr: Box<Expr>, else_expr: Box<Expr> },
    Index { array: Box<Expr>, index: Box<Expr> },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
    Neg,
    Not,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Lt,
    Le,
    Gt,
    Ge,
    Eq,
    Ne,
    And,
    Or,
}
