#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
    TritLiteral(i8),
    IntLiteral(i64),
    FloatLiteral(f64),
    StringLiteral(String),
    Ident(String),
    BinaryOp {
        op: BinOp,
        lhs: Box<Expr>,
        rhs: Box<Expr>,
    },
    UnaryOp {
        op: UnOp,
        expr: Box<Expr>,
    },
    Call {
        callee: String,
        args: Vec<Expr>,
    },
    /// field access: `object.field`
    FieldAccess {
        object: Box<Expr>,
        field: String,
    },
    /// cast(expr) — type coercion built-in
    Cast {
        expr: Box<Expr>,
        ty: Type,
    },
    /// spawn AgentName — creates a local agent instance, evaluates to AgentRef
    /// spawn remote "addr" AgentName — creates a remote agent instance (Phase 5.1)
    Spawn {
        agent_name: String,
        /// None = local, Some("host:port") = remote node
        node_addr: Option<String>,
    },
    /// await <agentref_expr> — receive result from agent mailbox
    Await {
        target: Box<Expr>,
    },
    /// tensor[10..20] slice
    Slice {
        object: Box<Expr>,
        start: Box<Expr>,
        end: Box<Expr>,
        stride: Box<Expr>,
    },
    /// tensor[row, col] indexing (Phase 4.1)
    Index {
        object: Box<Expr>,
        row: Box<Expr>,
        col: Box<Expr>,
    },
    /// nodeid — returns the current node's address (Phase 5.1)
    NodeId,
    /// expr? — ternary error propagation.
    /// If the inner expression evaluates to -1 (conflict), the current function
    /// returns -1 immediately.  Otherwise execution continues with the value.
    Propagate {
        expr: Box<Expr>,
    },
    /// [1, 0, -1]
    TritTensorLiteral(Vec<i8>),
    /// Struct initialization: `Name { field: value, ... }`
    StructLiteral {
        name: String,
        fields: Vec<(String, Expr)>,
    },
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BinOp {
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Equal,
    NotEqual,
    Less,
    Greater,
    LessEqual,
    GreaterEqual,
    And,
    Or,
}

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

#[derive(Debug, Clone, PartialEq)]
pub enum Stmt {
    Let {
        name: String,
        ty: Type,
        value: Expr,
    },
    IfTernary {
        condition: Expr,
        on_pos: Box<Stmt>,   // branch when +1
        on_zero: Box<Stmt>,  // branch when  0
        on_neg: Box<Stmt>,   // branch when -1
    },
    Match {
        condition: Expr,
        arms: Vec<(Pattern, Stmt)>,
    },
    /// for <var> in <iter_expr> { body }
    ForIn {
        var: String,
        iter: Expr,
        body: Box<Stmt>,
    },
    /// while <condition> ? { on_pos } else { on_zero } else { on_neg }
    WhileTernary {
        condition: Expr,
        on_pos: Box<Stmt>,
        on_zero: Box<Stmt>,
        on_neg: Box<Stmt>,
    },
    /// loop { body } — infinite loop, exited via break
    Loop {
        body: Box<Stmt>,
    },
    Break,
    Continue,
    Block(Vec<Stmt>),
    Return(Expr),
    Expr(Expr),
    Decorated {
        directive: String,
        stmt: Box<Stmt>,
    },
    /// use path::to::module;
    Use {
        path: Vec<String>,
    },
    /// from <source> import <names>;
    FromImport {
        spec: ImportSpec,
    },
    /// send <agentref_expr> <message_expr>;
    Send {
        target: Expr,
        message: Expr,
    },
    /// instance.field = value;
    FieldSet {
        object: String,
        field: String,
        value: Expr,
    },
    /// tensor[row, col] = value;
    IndexSet {
        object: String,
        row: Expr,
        col: Expr,
        value: Expr,
    },
    /// ident = value;
    Set {
        name: String,
        value: Expr,
    },
}

#[derive(Debug, Clone, PartialEq)]
pub enum Pattern {
    Int(i64),
    Trit(i8),
    Float(f64),
    Wildcard,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Type {
    Trit,
    TritTensor { dims: Vec<usize> },
    PackedTritTensor { dims: Vec<usize> },
    Int,
    IntTensor { dims: Vec<usize> },
    Bool,
    Float,
    FloatTensor { dims: Vec<usize> },
    String,
    /// User-defined struct type
    Named(String),
    /// Handle to a running agent instance
    AgentRef,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Function {
    pub name: String,
    /// Generic size parameters, e.g. `<N, K>` in `fn foo<N, K>(a: trit[N]) -> trit[K]`.
    /// Each is a name bound to a wildcard TritTensor dim (dim=0) during type-checking.
    pub type_params: Vec<String>,
    pub params: Vec<(String, Type)>,
    pub return_type: Type,
    pub body: Vec<Stmt>,
    pub directive: Option<String>,
}

/// Top-level struct definition: `struct Name { field: type, ... }`
#[derive(Debug, Clone, PartialEq)]
pub struct StructDef {
    pub name: String,
    pub fields: Vec<(String, Type)>,
}

/// Top-level agent definition: `agent Name { fn handle(msg: trit) -> trit { ... } }`
/// v0.1: agents have a single `handle` method that processes each incoming message.
#[derive(Debug, Clone, PartialEq)]
pub struct AgentDef {
    pub name: String,
    pub methods: Vec<Function>,
}

/// Source of a `from ... import` statement.
#[derive(Debug, Clone, PartialEq)]
pub enum ImportSource {
    /// `from stdlib::net` — double-colon module path (stdlib or relative .tern)
    Module(Vec<String>),
    /// `from "path/to/file.tern"` — explicit file path (string literal)
    File(String),
}

/// What to pull out of the import source.
#[derive(Debug, Clone, PartialEq)]
pub enum ImportNames {
    /// `import *` — everything (same as legacy `use`)
    Wildcard,
    /// `import foo, bar` — only these named symbols
    Named(Vec<String>),
}

/// A `from <source> import <names>` statement.
#[derive(Debug, Clone, PartialEq)]
pub struct ImportSpec {
    pub source: ImportSource,
    pub names: ImportNames,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Program {
    /// Legacy `use std::trit;` paths (kept for backward compat)
    pub imports: Vec<Vec<String>>,
    /// New `from ... import ...` statements
    pub import_specs: Vec<ImportSpec>,
    pub structs: Vec<StructDef>,
    pub agents: Vec<AgentDef>,
    pub functions: Vec<Function>,
}
