// 当前仅支持 void、i32 和 i32*。
#include "ir/IR.h"
#include <unordered_map>
#include <functional>

namespace ir {

// 用于缓存复合类型的静态映射（简单实现）
static std::unordered_map<std::size_t, std::shared_ptr<Type>> pointer_cache;
static std::unordered_map<std::size_t, std::shared_ptr<Type>> array_cache;
static std::unordered_map<std::size_t, std::shared_ptr<Type>> function_cache;

// 简单哈希组合函数
static std::size_t hash_combine(std::size_t seed, std::size_t v) {
    return seed ^ (v + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}

Type::Type(Kind k) : kind_(k) {}

const std::shared_ptr<Type>& Type::GetVoidType() {
  static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Void);
  return type;
}

const std::shared_ptr<Type>& Type::GetInt32Type() {
  static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Int32);
  return type;
}

const std::shared_ptr<Type>& Type::GetFloat32Type() {
  static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Float32);
  return type;
}

const std::shared_ptr<Type>& Type::GetLabelType() {
  static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Label);
  return type;
}

// 兼容旧的 i32* 类型，返回指向 i32 的指针类型
const std::shared_ptr<Type>& Type::GetPtrInt32Type() {
  static const std::shared_ptr<Type> type = GetPointerType(GetInt32Type());
  return type;
}

std::shared_ptr<Type> Type::GetPointerType(std::shared_ptr<Type> pointee) {
  // 简单缓存：使用 pointee 的地址作为键（实际应使用更可靠的标识，但作为演示足够）
  std::size_t key = reinterpret_cast<std::size_t>(pointee.get());
  auto it = pointer_cache.find(key);
  if (it != pointer_cache.end()) {
    return it->second;
  }
  auto ptr_type = std::make_shared<PointerType>(pointee);
  pointer_cache[key] = ptr_type;
  return ptr_type;
}

std::shared_ptr<Type> Type::GetArrayType(std::shared_ptr<Type> elem, size_t size) {
  // 使用元素类型指针和大小组合哈希
  std::size_t seed = 0;
  seed = hash_combine(seed, reinterpret_cast<std::size_t>(elem.get()));
  seed = hash_combine(seed, size);
  auto it = array_cache.find(seed);
  if (it != array_cache.end()) {
    return it->second;
  }
  auto arr_type = std::make_shared<ArrayType>(elem, size);
  array_cache[seed] = arr_type;
  return arr_type;
}

std::shared_ptr<Type> Type::GetFunctionType(std::shared_ptr<Type> ret,
                                            std::vector<std::shared_ptr<Type>> params) {
  // 哈希组合：返回类型 + 参数类型列表
  std::size_t seed = reinterpret_cast<std::size_t>(ret.get());
  for (const auto& p : params) {
    seed = hash_combine(seed, reinterpret_cast<std::size_t>(p.get()));
  }
  auto it = function_cache.find(seed);
  if (it != function_cache.end()) {
    return it->second;
  }
  auto func_type = std::make_shared<FunctionType>(ret, std::move(params));
  function_cache[seed] = func_type;
  return func_type;
}

Type::Kind Type::GetKind() const { return kind_; }

bool Type::IsVoid() const { return kind_ == Kind::Void; }

bool Type::IsInt32() const { return kind_ == Kind::Int32; }

bool Type::IsFloat32() const { return kind_ == Kind::Float32; }

bool Type::IsPointer() const { return kind_ == Kind::Pointer; }

bool Type::IsArray() const { return kind_ == Kind::Array; }

bool Type::IsFunction() const { return kind_ == Kind::Function; }

bool Type::IsLabel() const { return kind_ == Kind::Label; }

// 兼容旧代码，检查是否为 i32* 类型
bool Type::IsPtrInt32() const {
  if (!IsPointer()) return false;
  const auto* ptr_ty = static_cast<const PointerType*>(this);
  return ptr_ty->GetPointeeType()->IsInt32();
}

// 检查是否为 float32* 类型
bool Type::IsPtrFloat32() const {
  if (!IsPointer()) return false;
  const auto* ptr_ty = static_cast<const PointerType*>(this);
  return ptr_ty->GetPointeeType()->IsFloat32();
}

bool Type::operator==(const Type& other) const {
  if (kind_ != other.kind_) return false;
  
  switch (kind_) {
    case Kind::Void:
    case Kind::Int32:
    case Kind::Float32:
    case Kind::Label:
      return true;
    case Kind::Pointer: {
      const auto* this_ptr = static_cast<const PointerType*>(this);
      const auto* other_ptr = static_cast<const PointerType*>(&other);
      return *this_ptr->GetPointeeType() == *other_ptr->GetPointeeType();
    }
    case Kind::Array: {
      const auto* this_arr = static_cast<const ArrayType*>(this);
      const auto* other_arr = static_cast<const ArrayType*>(&other);
      return this_arr->GetSize() == other_arr->GetSize() &&
             *this_arr->GetElementType() == *other_arr->GetElementType();
    }
    case Kind::Function: {
      const auto* this_func = static_cast<const FunctionType*>(this);
      const auto* other_func = static_cast<const FunctionType*>(&other);
      if (*this_func->GetReturnType() != *other_func->GetReturnType()) return false;
      const auto& this_params = this_func->GetParamTypes();
      const auto& other_params = other_func->GetParamTypes();
      if (this_params.size() != other_params.size()) return false;
      for (size_t i = 0; i < this_params.size(); ++i) {
        if (*this_params[i] != *other_params[i]) return false;
      }
      return true;
    }
    default:
      return false;
  }
}

bool Type::operator!=(const Type& other) const {
  return !(*this == other);
}

}  // namespace ir