#include "irgen/IRGen.h"

#include <stdexcept>

#include "SysYParser.h"
#include "ir/IR.h"
#include "utils/Log.h"

namespace {

void VerifyFunctionStructure(const ir::Function& func) {
  // 当前 IRGen 仍是单入口、顺序生成；这里在生成结束后补一层块终结校验。
  for (const auto& bb : func.GetBlocks()) {
    if (!bb || !bb->HasTerminator()) {
      throw std::runtime_error(
          FormatError("irgen", "基本块未正确终结: " +
                                   (bb ? bb->GetName() : std::string("<null>"))));
    }
  }
}

}  // namespace

IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
    : module_(module),
      sema_(sema),
      func_(nullptr),
      builder_(module.GetContext(), nullptr) {}

// 编译单元的 IR 生成当前只实现了最小功能：
// - Module 已在 GenerateIR 中创建，这里只负责继续生成其中的内容；
// - 当前会读取编译单元中的函数定义，并交给 visitFuncDef 生成函数 IR；
//
// 当前还没有实现：
// - 多个函数定义的遍历与生成；
// - 全局变量、全局常量的 IR 生成。
std::any IRGenImpl::visitCompUnit(SysYParser::CompUnitContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "缺少编译单元"));
  }
  auto* func = ctx->funcDef();
  if (!func) {
    throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
  }
  func->accept(this);
  return {};
}

// 函数 IR 生成当前实现了：
// 1. 获取函数名；
// 2. 检查函数返回类型；
// 3. 在 Module 中创建 Function；
// 4. 将 builder 插入点设置到入口基本块；
// 5. 继续生成函数体。
//
// 当前还没有实现：
// - 通用函数返回类型处理；
// - 形参列表遍历与参数类型收集；
// - FunctionType 这样的函数类型对象；
// - Argument/形式参数 IR 对象；
// - 入口块中的参数初始化逻辑。
// ...

// 因此这里目前只支持最小的“无参 int 函数”生成。
std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
  }
  if (!ctx->blockStmt()) {
    throw std::runtime_error(FormatError("irgen", "函数体为空"));
  }
  if (!ctx->ID()) {
    throw std::runtime_error(FormatError("irgen", "缺少函数名"));
  }
  if (!ctx->funcType() || !ctx->funcType()->INT()) {
    throw std::runtime_error(FormatError("irgen", "当前仅支持无参 int 函数"));
  }

  func_ = module_.CreateFunction(ctx->ID()->getText(), ir::Type::GetInt32Type());
  builder_.SetInsertPoint(func_->GetEntry());
  storage_map_.clear();

  ctx->blockStmt()->accept(this);
  // 语义正确性主要由 sema 保证，这里只兜底检查 IR 结构是否合法。
  VerifyFunctionStructure(*func_);
  return {};
}
