use crate::{ast::types::{BinaryOp, UnaryOp}, diagnostic::span::Span, sema::{symbol::{FunctionId, FunctionSig, SymbolId}, types::SemaType}};

pub struct HirCompileUnit {
    pub global_decls: Vec<HirGlobalDeclStmt>,
}

pub enum HirGlobalDeclStmt {
    VarDecl(HirVarDeclStmt),
    FuncDecl(HirFuncDeclStmt),
}

pub struct HirVarDeclStmt {
    pub values: Vec<HirVarDeclStmtValue>,
    pub data_type: SemaType,
    pub type_span: Span,
}

pub struct HirVarDeclStmtValue {
    pub symbol: SymbolId,
    pub name_span: Span,
    pub value: Option<HirExpr>,
    pub is_static_local: bool,
}

pub struct HirFuncDeclStmt {
    pub sig: FunctionSig,
    pub params: Vec<HirParam>,
    pub body: HirBlockStmt,
    pub ret_type_span: Span,
    pub name_span: Span,
}

pub struct HirParam {
    pub symbol: SymbolId,
    pub param_type: SemaType,
    pub name_span: Span,
    pub type_span: Span,
}

pub struct HirBlockStmt {
    pub statements: Vec<HirStatement>,
}

pub enum HirStatement {
    Return(HirReturnStmt),
    Block(HirBlockStmt),
    Expr(HirExpr),
    VarDecl(HirVarDeclStmt),
    If(HirIfStmt),
    While(HirWhileStmt),
    For(HirForStmt),
    Break(HirBreakStmt),
    Continue(HirContinueStmt),
}

pub struct HirIfStmt {
    pub condition: HirExpr,
    pub then_branch: HirBlockStmt,
    pub ifelse_branch: Vec<HirIfElseBranch>,
    pub else_branch: Option<HirBlockStmt>,
}

pub struct HirIfElseBranch {
    pub condition: HirExpr,
    pub then_branch: HirBlockStmt,
}

pub struct HirWhileStmt {
    pub condition: HirExpr,
    pub body: HirBlockStmt,
}

pub struct HirForStmt {
    pub init: Option<HirForInit>,
    pub condition: Option<HirExpr>,
    pub update: Option<HirExpr>,
    pub body: HirBlockStmt,
}

pub enum HirForInit {
    Expr(HirExpr),
    VarDecl(HirVarDeclStmt),
}

pub struct HirBreakStmt {
    pub span: Span,
}

pub struct HirContinueStmt {
    pub span: Span,
}

pub struct HirReturnStmt {
    pub value: Option<HirExpr>,
    pub span: Span,
}

pub struct HirExpr {
    pub value: HirExprValue,
    pub ty: SemaType,
    pub span: Span,
}

pub enum HirExprValue {
    IntLit(i64),
    Var(SymbolId),
    ArrayAccess {
        array: Box<HirExpr>,
        index: Box<HirExpr>,
    },
    BinaryOp {
        lhs: Box<HirExpr>,
        op: BinaryOp,
        rhs: Box<HirExpr>,
    },
    UnaryOp {
        op: UnaryOp,
        operand: Box<HirExpr>,
    },
    IncDec {
        op: crate::ast::types::IncDecOp,
        operand: Box<HirExpr>,
        is_prefix: bool,
    },
    FuncCall(FunctionId, Vec<HirExpr>),
    Assign {
        lvalue: Box<HirExpr>,
        rvalue: Box<HirExpr>,
    },
    CompoundAssign {
        lvalue: Box<HirExpr>,
        op: BinaryOp,
        rvalue: Box<HirExpr>,
    },
}
