#include "irgen/IRGen.h"

#include <stdexcept>

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

ir::Value* IRGenImpl::EvalExpr(SysYParser::ExpContext& expr) {
  return std::any_cast<ir::Value*>(expr.accept(this));
}

ir::Value* IRGenImpl::EvalCond(SysYParser::CondContext& cond) {
  return std::any_cast<ir::Value*>(cond.accept(this));
}

ir::Value* IRGenImpl::ToBoolValue(ir::Value* v) {
  if (!v) {
    throw std::runtime_error(FormatError("irgen", "条件值为空"));
  }
  if (v->GetType() && v->GetType()->IsPtrInt32()) {
    // SysY 中数组名退化得到的指针在当前实现里总是非空。
    return builder_.CreateConstInt(1);
  }
  if (dynamic_cast<ir::CmpInst*>(v) != nullptr) {
    return v;
  }
  auto* zero = builder_.CreateConstInt(0);
  return builder_.CreateCmp(ir::CmpOp::Ne, v, zero, module_.GetContext().NextTemp());
}

std::string IRGenImpl::NextBlockName() {
  std::string temp = module_.GetContext().NextTemp();
  if (!temp.empty() && temp.front() == '%') {
    return "bb" + temp.substr(1);
  }
  return "bb" + temp;
}

// ─── 数组维度查找 ────────────────────────────────────────────────────────
const std::vector<int>* IRGenImpl::FindArrayDims(const std::string& name) const {
  auto it = local_array_dims_.find(name);
  if (it != local_array_dims_.end()) return &it->second;
  // 局部同名标量（含形参/局部变量）应屏蔽全局数组维度信息。
  if (named_storage_.find(name) != named_storage_.end()) return nullptr;
  auto git = global_array_dims_.find(name);
  if (git != global_array_dims_.end()) return &git->second;
  return nullptr;
}

// ─── 线性下标计算 ────────────────────────────────────────────────────────
// 给定维度 dims 和下标表达式列表，计算 linear = sum(subs[k] * stride[k])。
ir::Value* IRGenImpl::ComputeLinearIndex(
    const std::vector<int>& dims,
    const std::vector<SysYParser::ExpContext*>& subs) {
  // 对于 dims=[d0,d1,...,dn-1]，stride[k] = d_{k+1} * ... * d_{n-1}
  // 允许 dims[0] == -1（数组参数首维未知）
  ir::Value* linear = builder_.CreateConstInt(0);
  for (int k = 0; k < (int)subs.size() && k < (int)dims.size(); k++) {
    int stride = 1;
    for (int j = k + 1; j < (int)dims.size(); j++) stride *= dims[j];

    ir::Value* idx = EvalExpr(*subs[k]);
    if (stride != 1) {
      auto* sv = builder_.CreateConstInt(stride);
      idx = builder_.CreateMul(idx, sv, module_.GetContext().NextTemp());
    }
    linear = (stride == 1 && k == (int)subs.size() - 1 &&
              dynamic_cast<ir::ConstantInt*>(linear) &&
              static_cast<ir::ConstantInt*>(linear)->GetValue() == 0)
                 ? idx
                 : builder_.CreateAdd(linear, idx, module_.GetContext().NextTemp());
  }
  return linear;
}

std::any IRGenImpl::visitExp(SysYParser::ExpContext* ctx) {
  if (!ctx || !ctx->addExp()) {
    throw std::runtime_error(FormatError("irgen", "非法表达式"));
  }
  return ctx->addExp()->accept(this);
}

std::any IRGenImpl::visitCond(SysYParser::CondContext* ctx) {
  if (!ctx || !ctx->lOrExp()) {
    throw std::runtime_error(FormatError("irgen", "非法条件表达式"));
  }
  return ctx->lOrExp()->accept(this);
}

std::any IRGenImpl::visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "非法基本表达式"));
  }
  if (ctx->exp()) {
    return EvalExpr(*ctx->exp());
  }
  if (ctx->number()) {
    return ctx->number()->accept(this);
  }
  if (ctx->lValue()) {
    return ctx->lValue()->accept(this);
  }
  throw std::runtime_error(FormatError("irgen", "不支持的基本表达式"));
}

std::any IRGenImpl::visitNumber(SysYParser::NumberContext* ctx) {
  if (!ctx || !ctx->ILITERAL()) {
    throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量"));
  }
  // 支持十六进制和八进制字面量
  const std::string text = ctx->getText();
  int val = 0;
  if (text.size() >= 2 && text[0] == '0' &&
      (text[1] == 'x' || text[1] == 'X')) {
    val = std::stoi(text, nullptr, 16);
  } else if (text.size() > 1 && text[0] == '0') {
    val = std::stoi(text, nullptr, 8);
  } else {
    val = std::stoi(text);
  }
  return static_cast<ir::Value*>(builder_.CreateConstInt(val));
}

// ─── 变量存储槽位查找（含下标 GEP）────────────────────────────────────────
// 返回 i32* 指针：
//   - 无下标：直接返回 alloca/arg/globalvar 槽位
//   - 有下标：计算线性偏移并生成 GEP 指令，返回元素指针
ir::Value* IRGenImpl::ResolveStorage(SysYParser::LValueContext* lvalue) {
  if (!lvalue || !lvalue->ID()) return nullptr;
  const std::string name = lvalue->ID()->getText();

  // 获取基础槽位（三级查找）
  ir::Value* base = nullptr;

  // 1. sema binding（处理同名变量遮蔽）
  auto* decl = sema_.ResolveVarUse(lvalue);
  if (decl) {
    auto it = storage_map_.find(decl);
    if (it != storage_map_.end()) base = it->second;
  }
  if (!base) {
    auto it = named_storage_.find(name);
    if (it != named_storage_.end()) base = it->second;
  }
  if (!base) {
    auto git = global_storage_.find(name);
    if (git != global_storage_.end()) base = git->second;
  }

  if (!base) return nullptr;

  // 无下标：直接返回槽位
  if (lvalue->exp().empty()) return base;

  // 有下标：计算线性 GEP
  const std::vector<int>* dims = FindArrayDims(name);
  if (!dims) {
    throw std::runtime_error(
        FormatError("irgen", "未找到数组维度信息: " + name));
  }

  ir::Value* linear = ComputeLinearIndex(*dims, lvalue->exp());
  return builder_.CreateGep(base, linear, module_.GetContext().NextTemp());
}

// ─── lValue 访问 ─────────────────────────────────────────────────────────
std::any IRGenImpl::visitLValue(SysYParser::LValueContext* ctx) {
  if (!ctx || !ctx->ID()) {
    throw std::runtime_error(FormatError("irgen", "非法左值"));
  }
  const std::string name = ctx->ID()->getText();

  if (ctx->exp().empty()) {
    // 无下标：标量读取 或 数组基址引用
    ir::Value* slot = ResolveStorage(ctx);
    if (!slot) {
      throw std::runtime_error(
          FormatError("irgen", "变量未找到存储槽位: " + name));
    }
    // 如果是数组名，返回基址指针（用于传参）。
    // 全局数组需要先退化为首元素指针，避免直接把 [N x i32]* 传给 i32* 形参。
    if (FindArrayDims(name) != nullptr) {
      if (auto* gv = dynamic_cast<ir::GlobalVariable*>(slot); gv && gv->IsArray()) {
        return static_cast<ir::Value*>(
            builder_.CreateGep(slot, builder_.CreateConstInt(0),
                               module_.GetContext().NextTemp()));
      }
      return static_cast<ir::Value*>(slot);
    }
    // 标量：加载值
    return static_cast<ir::Value*>(
        builder_.CreateLoad(slot, module_.GetContext().NextTemp()));
  }

  // 有下标：GEP + load
  ir::Value* elem_ptr = ResolveStorage(ctx);
  if (!elem_ptr) {
    throw std::runtime_error(
        FormatError("irgen", "数组元素指针解析失败: " + name));
  }
  const auto* dims = FindArrayDims(name);
  if (dims && ctx->exp().size() < dims->size()) {
    // 如 A[i]（A 为二维数组）应退化为指针，用于实参传递。
    return static_cast<ir::Value*>(elem_ptr);
  }
  return static_cast<ir::Value*>(
      builder_.CreateLoad(elem_ptr, module_.GetContext().NextTemp()));
}

std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "非法一元表达式"));
  }
  if (ctx->primaryExp()) {
    return ctx->primaryExp()->accept(this);
  }
  if (ctx->unaryOp() && ctx->unaryExp()) {
    ir::Value* v = std::any_cast<ir::Value*>(ctx->unaryExp()->accept(this));
    if (ctx->unaryOp()->SUB()) {
      auto* zero = builder_.CreateConstInt(0);
      return static_cast<ir::Value*>(builder_.CreateSub(
          zero, v, module_.GetContext().NextTemp()));
    }
    if (ctx->unaryOp()->ADD()) {
      return v;
    }
    if (ctx->unaryOp()->NOT()) {
      // !v  ≡  (v == 0)
      auto* zero = builder_.CreateConstInt(0);
      return static_cast<ir::Value*>(builder_.CreateCmp(
          ir::CmpOp::Eq, v, zero, module_.GetContext().NextTemp()));
    }
    throw std::runtime_error(FormatError("irgen", "未知一元运算符"));
  }
  if (ctx->ID()) {
    // 函数调用：ID '(' funcRParams? ')'
    const std::string callee_name = ctx->ID()->getText();
    ir::Function* callee = module_.FindFunction(callee_name);
    if (!callee) {
      throw std::runtime_error(
          FormatError("irgen", "未定义的函数: " + callee_name));
    }
    std::vector<ir::Value*> args;
    if (auto* rparams = ctx->funcRParams()) {
      for (auto* ep : rparams->exp()) {
        args.push_back(EvalExpr(*ep));
      }
    }
    const std::string name =
        callee->GetType()->IsVoid() ? "" : module_.GetContext().NextTemp();
    return static_cast<ir::Value*>(
        builder_.CreateCall(callee, args, name));
  }
  throw std::runtime_error(FormatError("irgen", "非法一元表达式"));
}

std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "非法乘法表达式"));
  }
  if (ctx->mulExp()) {
    if (!ctx->unaryExp()) {
      throw std::runtime_error(FormatError("irgen", "非法乘法表达式"));
    }
    ir::Value* lhs = std::any_cast<ir::Value*>(ctx->mulExp()->accept(this));
    ir::Value* rhs = std::any_cast<ir::Value*>(ctx->unaryExp()->accept(this));
    if (ctx->MUL()) {
      return static_cast<ir::Value*>(
          builder_.CreateMul(lhs, rhs, module_.GetContext().NextTemp()));
    }
    if (ctx->DIV()) {
      return static_cast<ir::Value*>(
          builder_.CreateDiv(lhs, rhs, module_.GetContext().NextTemp()));
    }
    if (ctx->MOD()) {
      return static_cast<ir::Value*>(
          builder_.CreateMod(lhs, rhs, module_.GetContext().NextTemp()));
    }
    throw std::runtime_error(FormatError("irgen", "非法乘法表达式"));
  }
  if (ctx->unaryExp()) {
    return ctx->unaryExp()->accept(this);
  }
  throw std::runtime_error(FormatError("irgen", "非法乘法表达式"));
}

std::any IRGenImpl::visitAddExp(SysYParser::AddExpContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "非法加法表达式"));
  }
  if (ctx->addExp()) {
    if (!ctx->mulExp()) {
      throw std::runtime_error(FormatError("irgen", "非法加法表达式"));
    }
    ir::Value* lhs = std::any_cast<ir::Value*>(ctx->addExp()->accept(this));
    ir::Value* rhs = std::any_cast<ir::Value*>(ctx->mulExp()->accept(this));
    if (ctx->ADD()) {
      return static_cast<ir::Value*>(
          builder_.CreateAdd(lhs, rhs, module_.GetContext().NextTemp()));
    }
    if (ctx->SUB()) {
      return static_cast<ir::Value*>(
          builder_.CreateSub(lhs, rhs, module_.GetContext().NextTemp()));
    }
    throw std::runtime_error(FormatError("irgen", "非法加法表达式"));
  }
  if (ctx->mulExp()) {
    return ctx->mulExp()->accept(this);
  }
  throw std::runtime_error(FormatError("irgen", "非法加法表达式"));
}

std::any IRGenImpl::visitRelExp(SysYParser::RelExpContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "非法关系表达式"));
  }
  if (ctx->relExp()) {
    if (!ctx->addExp()) {
      throw std::runtime_error(FormatError("irgen", "非法关系表达式"));
    }
    ir::Value* lhs = std::any_cast<ir::Value*>(ctx->relExp()->accept(this));
    ir::Value* rhs = std::any_cast<ir::Value*>(ctx->addExp()->accept(this));
    if (ctx->LT()) {
      return static_cast<ir::Value*>(builder_.CreateCmp(
          ir::CmpOp::Lt, lhs, rhs, module_.GetContext().NextTemp()));
    }
    if (ctx->LE()) {
      return static_cast<ir::Value*>(builder_.CreateCmp(
          ir::CmpOp::Le, lhs, rhs, module_.GetContext().NextTemp()));
    }
    if (ctx->GT()) {
      return static_cast<ir::Value*>(builder_.CreateCmp(
          ir::CmpOp::Gt, lhs, rhs, module_.GetContext().NextTemp()));
    }
    if (ctx->GE()) {
      return static_cast<ir::Value*>(builder_.CreateCmp(
          ir::CmpOp::Ge, lhs, rhs, module_.GetContext().NextTemp()));
    }
    throw std::runtime_error(FormatError("irgen", "非法关系表达式"));
  }
  if (ctx->addExp()) {
    return ctx->addExp()->accept(this);
  }
  throw std::runtime_error(FormatError("irgen", "非法关系表达式"));
}

std::any IRGenImpl::visitEqExp(SysYParser::EqExpContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "非法相等表达式"));
  }
  if (ctx->eqExp()) {
    if (!ctx->relExp()) {
      throw std::runtime_error(FormatError("irgen", "非法相等表达式"));
    }
    ir::Value* lhs = std::any_cast<ir::Value*>(ctx->eqExp()->accept(this));
    ir::Value* rhs = std::any_cast<ir::Value*>(ctx->relExp()->accept(this));
    if (ctx->EQ()) {
      return static_cast<ir::Value*>(builder_.CreateCmp(
          ir::CmpOp::Eq, lhs, rhs, module_.GetContext().NextTemp()));
    }
    if (ctx->NE()) {
      return static_cast<ir::Value*>(builder_.CreateCmp(
          ir::CmpOp::Ne, lhs, rhs, module_.GetContext().NextTemp()));
    }
    throw std::runtime_error(FormatError("irgen", "非法相等表达式"));
  }
  if (ctx->relExp()) {
    return ctx->relExp()->accept(this);
  }
  throw std::runtime_error(FormatError("irgen", "非法相等表达式"));
}

std::any IRGenImpl::visitLAndExp(SysYParser::LAndExpContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "非法逻辑与表达式"));
  }
  if (ctx->lAndExp()) {
    if (!ctx->eqExp()) {
      throw std::runtime_error(FormatError("irgen", "非法逻辑与表达式"));
    }
    // 短路求值：a && b
    // 使用函数级临时槽位（0=false，1=true），避免 phi 依赖和循环内动态 alloca。
    if (!short_circuit_slot_) {
      throw std::runtime_error(FormatError("irgen", "短路求值槽位未初始化"));
    }
    auto* slot = short_circuit_slot_;
    builder_.CreateStore(builder_.CreateConstInt(0), slot);

    auto* lhs = std::any_cast<ir::Value*>(ctx->lAndExp()->accept(this));
    auto* lhs_bool = ToBoolValue(lhs);
    auto* rhs_bb = func_->CreateBlock(NextBlockName());
    auto* true_bb = func_->CreateBlock(NextBlockName());
    auto* merge_bb = func_->CreateBlock(NextBlockName());

    builder_.CreateCondBr(lhs_bool, rhs_bb, merge_bb);

    builder_.SetInsertPoint(rhs_bb);
    auto* rhs = std::any_cast<ir::Value*>(ctx->eqExp()->accept(this));
    auto* rhs_bool = ToBoolValue(rhs);
    builder_.CreateCondBr(rhs_bool, true_bb, merge_bb);

    builder_.SetInsertPoint(true_bb);
    builder_.CreateStore(builder_.CreateConstInt(1), slot);
    builder_.CreateBr(merge_bb);

    builder_.SetInsertPoint(merge_bb);
    return static_cast<ir::Value*>(
        builder_.CreateLoad(slot, module_.GetContext().NextTemp()));
  }
  if (ctx->eqExp()) {
    return ToBoolValue(std::any_cast<ir::Value*>(ctx->eqExp()->accept(this)));
  }
  throw std::runtime_error(FormatError("irgen", "非法逻辑与表达式"));
}

std::any IRGenImpl::visitLOrExp(SysYParser::LOrExpContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "非法逻辑或表达式"));
  }
  if (ctx->lOrExp()) {
    if (!ctx->lAndExp()) {
      throw std::runtime_error(FormatError("irgen", "非法逻辑或表达式"));
    }
    // 短路求值：a || b
    if (!short_circuit_slot_) {
      throw std::runtime_error(FormatError("irgen", "短路求值槽位未初始化"));
    }
    auto* slot = short_circuit_slot_;
    builder_.CreateStore(builder_.CreateConstInt(0), slot);

    auto* lhs = std::any_cast<ir::Value*>(ctx->lOrExp()->accept(this));
    auto* lhs_bool = ToBoolValue(lhs);
    auto* true_bb = func_->CreateBlock(NextBlockName());
    auto* rhs_bb = func_->CreateBlock(NextBlockName());
    auto* merge_bb = func_->CreateBlock(NextBlockName());

    builder_.CreateCondBr(lhs_bool, true_bb, rhs_bb);

    builder_.SetInsertPoint(true_bb);
    builder_.CreateStore(builder_.CreateConstInt(1), slot);
    builder_.CreateBr(merge_bb);

    builder_.SetInsertPoint(rhs_bb);
    auto* rhs = std::any_cast<ir::Value*>(ctx->lAndExp()->accept(this));
    auto* rhs_bool = ToBoolValue(rhs);
    auto* true2_bb = func_->CreateBlock(NextBlockName());
    builder_.CreateCondBr(rhs_bool, true2_bb, merge_bb);

    builder_.SetInsertPoint(true2_bb);
    builder_.CreateStore(builder_.CreateConstInt(1), slot);
    builder_.CreateBr(merge_bb);

    builder_.SetInsertPoint(merge_bb);
    return static_cast<ir::Value*>(
        builder_.CreateLoad(slot, module_.GetContext().NextTemp()));
  }
  if (ctx->lAndExp()) {
    return ToBoolValue(std::any_cast<ir::Value*>(ctx->lAndExp()->accept(this)));
  }
  throw std::runtime_error(FormatError("irgen", "非法逻辑或表达式"));
}
