///|
pub impl Eq for Module with fn equal(l, r) {
  let l_custom = l.custom_secs
  let r_custom = r.custom_secs
  if l_custom.length() != r_custom.length() {
    return false
  }
  for lc in l_custom {
    if !r_custom.contains(lc) {
      return false
    }
  }
  for rc in r_custom {
    if !l_custom.contains(rc) {
      return false
    }
  }
  l.type_sec == r.type_sec &&
  l.name_sec == r.name_sec &&
  l.compiler_fact_custom_section == r.compiler_fact_custom_section &&
  l.import_sec == r.import_sec &&
  l.func_annotation_sec == r.func_annotation_sec &&
  l.func_sec == r.func_sec &&
  l.table_sec == r.table_sec &&
  l.mem_sec == r.mem_sec &&
  l.tag_sec == r.tag_sec &&
  l.stringrefs_sec == r.stringrefs_sec &&
  l.global_sec == r.global_sec &&
  l.export_sec == r.export_sec &&
  l.start_sec == r.start_sec &&
  l.elem_sec == r.elem_sec &&
  l.data_cnt_sec == r.data_cnt_sec &&
  l.code_sec == r.code_sec &&
  l.data_sec == r.data_sec
}

///|
pub impl Eq for RecType with fn equal(l, r) {
  match (l, r) {
    (SingleRecType(stl), GroupRecType([str])) => stl == str
    (GroupRecType([stl]), SingleRecType(str)) => stl == str
    (SingleRecType(stl), SingleRecType(str)) => stl == str
    (GroupRecType(stl), GroupRecType(str)) => stl == str
    _ => false
  }
}

///|
pub impl Eq for RefType with fn equal(l, r) {
  match (l, r) {
    (HeapTypeRefType(l0, l1, l2), HeapTypeRefType(r0, r1, r2)) =>
      l0 == r0 && l1 == r1 && l2 == r2
    (AbsHeapTypeRefType(l0), AbsHeapTypeRefType(r0)) => l0 == r0
    (
      AbsHeapTypeRefType(l0),
      HeapTypeRefType(true, false, AbsHeapTypeHeapType(r0)),
    ) => l0 == r0
    (
      HeapTypeRefType(true, false, AbsHeapTypeHeapType(l0)),
      AbsHeapTypeRefType(r0),
    ) => l0 == r0
    _ => false
  }
}

///|
pub impl Eq for MemArg with fn equal(l, r) {
  l.0 == r.0 &&
  l.1.unwrap_or(MemIdx(0)) == r.1.unwrap_or(MemIdx(0)) &&
  l.2 == r.2
}

///|
test "RecType equality edge cases" {
  let st = SubType::comp_type(FuncCompType([], []))

  // SingleRecType should equal GroupRecType with single element
  @debug.assert_eq(SingleRecType(st), GroupRecType([st]))
  @debug.assert_eq(GroupRecType([st]), SingleRecType(st))

  // But different subtypes should not be equal
  let st2 = SubType::comp_type(FuncCompType([NumTypeValType(I32NumType)], []))
  assert_not_eq(SingleRecType(st), SingleRecType(st2))
  assert_not_eq(SingleRecType(st), GroupRecType([st2]))

  // Multiple elements should not equal single
  assert_not_eq(GroupRecType([st, st]), SingleRecType(st))
}

///|
test "RefType equality edge cases" {
  // AbsHeapTypeRefType should equal HeapTypeRefType with nullable + AbsHeapTypeHeapType
  @debug.assert_eq(
    AbsHeapTypeRefType(FuncAbsHeapType),
    HeapTypeRefType(true, false, AbsHeapTypeHeapType(FuncAbsHeapType)),
  )
  @debug.assert_eq(
    HeapTypeRefType(true, false, AbsHeapTypeHeapType(ExternAbsHeapType)),
    AbsHeapTypeRefType(ExternAbsHeapType),
  )

  // Non-nullable should NOT equal AbsHeapTypeRefType
  assert_not_eq(
    AbsHeapTypeRefType(FuncAbsHeapType),
    HeapTypeRefType(false, false, AbsHeapTypeHeapType(FuncAbsHeapType)),
  )

  // Different heap types should not be equal
  assert_not_eq(
    AbsHeapTypeRefType(FuncAbsHeapType),
    AbsHeapTypeRefType(ExternAbsHeapType),
  )
  assert_not_eq(
    AbsHeapTypeRefType(FuncAbsHeapType),
    HeapTypeRefType(true, false, AbsHeapTypeHeapType(ExternAbsHeapType)),
  )
}

///|
test "MemArg equality edge cases" {
  // None memidx should equal Some(MemIdx(0))
  @debug.assert_eq(
    MemArg(U32(0), None, U64(0)),
    MemArg(U32(0), Some(MemIdx(0)), U64(0)),
  )
  @debug.assert_eq(
    MemArg(U32(4), None, U64(8)),
    MemArg(U32(4), Some(MemIdx(0)), U64(8)),
  )

  // But Some(MemIdx(1)) should NOT equal None
  assert_not_eq(
    MemArg(U32(0), None, U64(0)),
    MemArg(U32(0), Some(MemIdx(1)), U64(0)),
  )

  // Different align/offset should not be equal
  assert_not_eq(MemArg(U32(0), None, U64(0)), MemArg(U32(1), None, U64(0)))
  assert_not_eq(MemArg(U32(0), None, U64(0)), MemArg(U32(0), None, U64(1)))
}

///|
test "HeapType equality - verify transformer changes are detected" {
  // These should NOT be equal - this is what HeapTypeSwap produces
  let before : HeapType = AbsHeapTypeHeapType(FuncAbsHeapType)
  let after : HeapType = AbsHeapTypeHeapType(ExternAbsHeapType)
  assert_not_eq(before, after)

  // TypeIdx changes should be detected
  let idx_before : HeapType = HeapType(TypeIdx(0))
  let idx_after : HeapType = HeapType(TypeIdx(1000))
  assert_not_eq(idx_before, idx_after)
}

///|
test "RefType with transformed HeapType should not be equal" {
  // The transformer changes HeapType inside RefType
  let before = HeapTypeRefType(
    true,
    false,
    AbsHeapTypeHeapType(FuncAbsHeapType),
  )
  let after = HeapTypeRefType(
    true,
    false,
    AbsHeapTypeHeapType(ExternAbsHeapType),
  )
  assert_not_eq(before, after)

  // But AbsHeapTypeRefType doesn't contain HeapType - verify these are different
  let abs_func = AbsHeapTypeRefType(FuncAbsHeapType)
  let abs_extern = AbsHeapTypeRefType(ExternAbsHeapType)
  assert_not_eq(abs_func, abs_extern)
}