module Tapioca::Runtime::Trackers::Mixin

def constants_with_mixin(mixin)

: (Module mixin) -> Hash[Type, Hash[Module, String]]
def constants_with_mixin(mixin)
  find_or_initialize_mixin_lookup(mixin)
end

def find_or_initialize_mixin_lookup(mixin)

: (Module mixin) -> Hash[Type, Hash[Module, String]]
def find_or_initialize_mixin_lookup(mixin)
  @mixins_to_constants[mixin] ||= {
    Type::Prepend => {}.compare_by_identity,
    Type::Include => {}.compare_by_identity,
    Type::Extend => {}.compare_by_identity,
  }
end

def mixin_location(mixin, mixin_type, constant)

: (Module mixin, Type mixin_type, Module constant) -> String?
def mixin_location(mixin, mixin_type, constant)
  find_or_initialize_mixin_lookup(mixin).dig(mixin_type, constant)
end

def register(constant, mixin, mixin_type)

: (Module constant, Module mixin, Type mixin_type) -> void
def register(constant, mixin, mixin_type)
  return unless enabled?
  location = Reflection.resolve_loc(caller_locations)
  return unless location
  register_with_location(constant, mixin, mixin_type, location.file)
end

def register_with_location(constant, mixin, mixin_type, location)

: (Module constant, Module mixin, Type mixin_type, String location) -> void
def register_with_location(constant, mixin, mixin_type, location)
  return unless @enabled
  constants = find_or_initialize_mixin_lookup(mixin)
  constants.fetch(mixin_type).store(constant, location)
end

def resolve_to_attached_class(constant, mixin, mixin_type)

def resolve_to_attached_class(constant, mixin, mixin_type)
  attached_class = Reflection.attached_class_of(constant)
  return unless attached_class
  if mixin_type == Type::Include || mixin_type == Type::Prepend
    location = mixin_location(mixin, mixin_type, constant)
    register_with_location(constant, mixin, Type::Extend, T.must(location))
  end
  attached_class
end

def with_disabled_registration(&block)

: [Result] { -> Result } -> Result
def with_disabled_registration(&block)
  with_disabled_tracker(&block)
end