package org.jcnc.snow.compiler.ir.builder;

import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import org.jcnc.snow.compiler.parser.ast.AssignmentNode;
import org.jcnc.snow.compiler.parser.ast.DeclarationNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionStatementNode;
import org.jcnc.snow.compiler.parser.ast.ReturnNode;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;

/**
 * StatementBuilder 负责将解析器生成的语句 AST 节点（StatementNode）
 * 转换为编译器中间表示（IR）中的指令序列。
 * <p>
 * 支持的语句类型包括：
 * <ul>
 *   <li>表达式语句（ExpressionStatementNode）</li>
 *   <li>赋值语句（AssignmentNode）</li>
 *   <li>声明语句（DeclarationNode）</li>
 *   <li>返回语句（ReturnNode）</li>
 * </ul>
 * 对于不支持的节点类型，方法会抛出 IllegalStateException。
 */
public class StatementBuilder {
    /** 当前的 IR 上下文，用于生成指令和管理作用域 */
    private final IRContext irContext;
    /** 用于生成表达式对应的 IR 寄存器和指令的构建器 */
    private final ExpressionBuilder exprBuilder;

    /**
     * 构造函数，初始化 IR 上下文并创建 ExpressionBuilder 实例。
     *
     * @param irContext IR 上下文对象，包含当前函数的作用域、指令列表等信息
     */
    public StatementBuilder(IRContext irContext) {
        this.irContext = irContext;
        this.exprBuilder = new ExpressionBuilder(irContext);
    }

    /**
     * 根据不同的语句节点类型，将其转换为相应的 IR 指令：
     * <ul>
     *   <li>ExpressionStatementNode：生成表达式指令，忽略返回值</li>
     *   <li>AssignmentNode：生成右侧表达式指令，将结果绑定到变量（第一次声明或更新）</li>
     *   <li>DeclarationNode：如带初始化器，则先生成初始化表达式指令，并声明变量；否则只声明变量</li>
     *   <li>ReturnNode：如带返回表达式，则生成带返回值的指令；否则生成无返回值指令</li>
     * </ul>
     *
     * @param statementNode 要构建的语句 AST 节点
     * @throws IllegalStateException 如果遇到不支持的语句类型，则抛出此异常
     */
    public void build(StatementNode statementNode) {
        // 表达式语句: 仅生成表达式对应的 IR 指令，不关注结果
        if (statementNode instanceof ExpressionStatementNode(
                ExpressionNode expression)) {
            exprBuilder.build(expression);
            return;
        }
        // 赋值语句: 先生成右侧表达式指令，获取寄存器，再声明或更新变量的值绑定
        if (statementNode instanceof AssignmentNode(
                String variable, ExpressionNode value
        )) {
            IRVirtualRegister irVirtualRegister = exprBuilder.build(value);
            if (irContext.getScope().lookup(variable) == null) {
                // 首次赋值：声明变量并绑定寄存器
                irContext.getScope().declare(variable, irVirtualRegister);
            } else {
                // 变量已存在：更新绑定的寄存器
                irContext.getScope().put(variable, irVirtualRegister);
            }
            return;
        }
        // 声明语句: 如有初始化表达式，则先构建初始化值并声明；否则直接声明变量
        if (statementNode instanceof DeclarationNode declarationNode) {
            if (declarationNode.getInitializer().isPresent()) {
                IRVirtualRegister irVirtualRegister = exprBuilder.build(declarationNode.getInitializer().get());
                irContext.getScope().declare(declarationNode.getName(), irVirtualRegister);
            } else {
                irContext.getScope().declare(declarationNode.getName());
            }
            return;
        }
        // 返回语句: 区分有返回值和无返回值两种情况
        if (statementNode instanceof ReturnNode returnNode) {
            if (returnNode.getExpression().isPresent()) {
                IRVirtualRegister irVirtualRegister = exprBuilder.build(returnNode.getExpression().get());
                InstructionFactory.ret(irContext, irVirtualRegister);
            } else {
                InstructionFactory.retVoid(irContext);
            }
            return;
        }
        // 不支持的语句类型
        throw new IllegalStateException("Unsupported statement: " + statementNode.getClass().getSimpleName());
    }
}
