"""
TENGWAR AST Node Definitions

Every node in the TENGWAR Abstract Syntax Tree.
The source representation IS the AST — no lossy parsing step.
"""
from dataclasses import dataclass, field
from typing import Any
from enum import Enum, auto


class NodeType(Enum):
    # Literals
    INT = auto()
    FLOAT = auto()
    STRING = auto()
    BOOL = auto()
    UNIT = auto()       # ∅

    # Identifiers
    SYMBOL = auto()     # Regular symbol
    HASH_ID = auto()    # #abc content-addressed id
    ADDR_REF = auto()   # @abc address reference

    # Core forms
    LAMBDA = auto()     # λ
    BIND = auto()       # →
    COND = auto()       # ?
    MATCH = auto()      # ~
    SEQ = auto()        # >> (sequence/do)
    PARALLEL = auto()   # ∥
    MODULE = auto()     # □
    DEFINE = auto()     # :=
    RECURSE = auto()    # ↺
    TYPE_ANN = auto()   # τ
    PROOF = auto()      # ⊢
    EFFECT = auto()     # ⊕
    MUTATE = auto()     # μ

    # Collections
    TUPLE = auto()      # ⟨⟩
    VECTOR = auto()     # ⟦⟧

    # Application
    APPLY = auto()      # (f args...)

    # Binary / Unary ops
    BINOP = auto()
    UNOP = auto()

    # Special
    IMPORT = auto()
    EXPORT = auto()
    COMMENT = auto()    # ;; machine-readable metadata
    LET = auto()        # (let bindings body)
    PIPE = auto()       # (|> val f1 f2 f3)
    PY_IMPORT = auto()  # (py-import "module")
    THROW = auto()      # (throw expr)
    CATCH = auto()      # (catch expr handler)


@dataclass
class ASTNode:
    type: NodeType = None
    line: int = 0
    col: int = 0


@dataclass
class IntLit(ASTNode):
    value: int = 0
    def __post_init__(self):
        self.type = NodeType.INT


@dataclass
class FloatLit(ASTNode):
    value: float = 0.0
    def __post_init__(self):
        self.type = NodeType.FLOAT


@dataclass
class StrLit(ASTNode):
    value: str = ""
    def __post_init__(self):
        self.type = NodeType.STRING


@dataclass
class BoolLit(ASTNode):
    value: bool = False
    def __post_init__(self):
        self.type = NodeType.BOOL


@dataclass
class UnitLit(ASTNode):
    def __post_init__(self):
        self.type = NodeType.UNIT
        self.value = None


@dataclass
class Symbol(ASTNode):
    name: str = ""
    def __post_init__(self):
        self.type = NodeType.SYMBOL


@dataclass
class HashId(ASTNode):
    """Content-addressed identifier like #a3f"""
    hash: str = ""
    def __post_init__(self):
        self.type = NodeType.HASH_ID


@dataclass
class AddrRef(ASTNode):
    """Address reference like @e4c2"""
    addr: str = ""
    def __post_init__(self):
        self.type = NodeType.ADDR_REF


@dataclass
class Lambda(ASTNode):
    """(λ params body) or (λ params τ type body)"""
    params: list = field(default_factory=list)
    body: Any = None
    type_ann: Any = None  # Optional type annotation
    def __post_init__(self):
        self.type = NodeType.LAMBDA


@dataclass
class Bind(ASTNode):
    """expr → target"""
    expr: Any = None
    target: Any = None
    def __post_init__(self):
        self.type = NodeType.BIND


@dataclass
class Define(ASTNode):
    """:= name value"""
    name: Any = None
    value: Any = None
    def __post_init__(self):
        self.type = NodeType.DEFINE


@dataclass
class Cond(ASTNode):
    """(? condition then else)"""
    condition: Any = None
    then_branch: Any = None
    else_branch: Any = None
    def __post_init__(self):
        self.type = NodeType.COND


@dataclass
class Match(ASTNode):
    """(~ expr (pattern result)...)"""
    expr: Any = None
    cases: list = field(default_factory=list)  # List of (pattern, body) tuples
    def __post_init__(self):
        self.type = NodeType.MATCH


@dataclass
class Seq(ASTNode):
    """(>> expr1 expr2 ...) - sequential execution"""
    exprs: list = field(default_factory=list)
    def __post_init__(self):
        self.type = NodeType.SEQ


@dataclass
class Parallel(ASTNode):
    """(∥ expr1 expr2 ...) - parallel execution"""
    exprs: list = field(default_factory=list)
    def __post_init__(self):
        self.type = NodeType.PARALLEL


@dataclass
class Module(ASTNode):
    """(□ ...definitions)"""
    name: str = ""
    body: list = field(default_factory=list)
    def __post_init__(self):
        self.type = NodeType.MODULE


@dataclass
class Recurse(ASTNode):
    """(↺ name body) - explicit recursion"""
    name: Any = None
    body: Any = None
    def __post_init__(self):
        self.type = NodeType.RECURSE


@dataclass
class TypeAnn(ASTNode):
    """τ(type) - type annotation"""
    type_expr: Any = None
    def __post_init__(self):
        self.type = NodeType.TYPE_ANN


@dataclass
class Proof(ASTNode):
    """(⊢ assertion) - proof obligation"""
    assertion: Any = None
    def __post_init__(self):
        self.type = NodeType.PROOF


@dataclass
class Effect(ASTNode):
    """⊕{effects} - effect declaration"""
    effects: list = field(default_factory=list)
    def __post_init__(self):
        self.type = NodeType.EFFECT


@dataclass
class Mutate(ASTNode):
    """(μ name value) - mutable cell"""
    name: Any = None
    value: Any = None
    def __post_init__(self):
        self.type = NodeType.MUTATE


@dataclass
class Tuple(ASTNode):
    """⟨expr1 expr2 ...⟩"""
    elements: list = field(default_factory=list)
    def __post_init__(self):
        self.type = NodeType.TUPLE


@dataclass
class Vector(ASTNode):
    """⟦expr1 expr2 ...⟧"""
    elements: list = field(default_factory=list)
    def __post_init__(self):
        self.type = NodeType.VECTOR


@dataclass
class Apply(ASTNode):
    """(func arg1 arg2 ...)"""
    func: Any = None
    args: list = field(default_factory=list)
    def __post_init__(self):
        self.type = NodeType.APPLY


@dataclass
class BinOp(ASTNode):
    """(op left right)"""
    op: str = ""
    left: Any = None
    right: Any = None
    def __post_init__(self):
        self.type = NodeType.BINOP


@dataclass
class UnOp(ASTNode):
    """(op operand)"""
    op: str = ""
    operand: Any = None
    def __post_init__(self):
        self.type = NodeType.UNOP


@dataclass
class Import(ASTNode):
    """(⇐ @addr) - import module"""
    addr: Any = None
    def __post_init__(self):
        self.type = NodeType.IMPORT


@dataclass
class Let(ASTNode):
    """(let x 1 y 2 body) - local bindings"""
    bindings: list = field(default_factory=list)  # [(name, value), ...]
    body: Any = None
    def __post_init__(self):
        self.type = NodeType.LET


@dataclass
class Pipe(ASTNode):
    """(|> value f1 f2 f3) - pipe value through functions"""
    value: Any = None
    funcs: list = field(default_factory=list)
    def __post_init__(self):
        self.type = NodeType.PIPE


@dataclass
class Throw(ASTNode):
    """(throw expr) - throw an error"""
    expr: Any = None
    def __post_init__(self):
        self.type = NodeType.THROW


@dataclass
class Catch(ASTNode):
    """(catch expr handler) - catch errors"""
    expr: Any = None
    handler: Any = None
    def __post_init__(self):
        self.type = NodeType.CATCH


@dataclass
class PyImportNode(ASTNode):
    """(py-import \"module\") - import Python module"""
    module_name: Any = None
    alias: str = ""
    def __post_init__(self):
        self.type = NodeType.PY_IMPORT


@dataclass
class Comment(ASTNode):
    """;; metadata comment (machine-readable)"""
    content: str = ""
    metadata: dict = field(default_factory=dict)
    def __post_init__(self):
        self.type = NodeType.COMMENT


@dataclass
class Program(ASTNode):
    """Top-level program node"""
    body: list = field(default_factory=list)
    def __post_init__(self):
        self.type = None
