class RubyLsp::Listeners::DocumentSymbol

def create_document_symbol(name:, kind:, range_location:, selection_range_location:)

def create_document_symbol(name:, kind:, range_location:, selection_range_location:)
  symbol = Interface::DocumentSymbol.new(
    name: name,
    kind: kind,
    range: range_from_location(range_location),
    selection_range: range_from_location(selection_range_location),
    children: [],
  )
  @response_builder.last.children << symbol
  symbol
end

def handle_alias_method(node)

def handle_alias_method(node)
  receiver = node.receiver
  return if receiver && !receiver.is_a?(Prism::SelfNode)
  arguments = node.arguments
  return unless arguments
  new_name_argument = arguments.arguments.first
  if new_name_argument.is_a?(Prism::SymbolNode)
    name = new_name_argument.value
    return unless name
    create_document_symbol(
      name: name,
      kind: Constant::SymbolKind::METHOD,
      range_location: new_name_argument.location,
      selection_range_location: T.must(new_name_argument.value_loc),
    )
  elsif new_name_argument.is_a?(Prism::StringNode)
    name = new_name_argument.content
    return if name.empty?
    create_document_symbol(
      name: name,
      kind: Constant::SymbolKind::METHOD,
      range_location: new_name_argument.location,
      selection_range_location: new_name_argument.content_loc,
    )
  end
end

def handle_attr_accessor(node)

def handle_attr_accessor(node)
  return unless node.receiver.nil?
  arguments = node.arguments
  return unless arguments
  arguments.arguments.each do |argument|
    next unless argument.is_a?(Prism::SymbolNode)
    name = argument.value
    next unless name
    create_document_symbol(
      name: name,
      kind: Constant::SymbolKind::FIELD,
      range_location: argument.location,
      selection_range_location: T.must(argument.value_loc),
    )
  end
end

def initialize(response_builder, dispatcher)

def initialize(response_builder, dispatcher)
  @response_builder = response_builder
  dispatcher.register(
    self,
    :on_class_node_enter,
    :on_class_node_leave,
    :on_call_node_enter,
    :on_constant_path_write_node_enter,
    :on_constant_write_node_enter,
    :on_def_node_enter,
    :on_def_node_leave,
    :on_module_node_enter,
    :on_module_node_leave,
    :on_instance_variable_write_node_enter,
    :on_class_variable_write_node_enter,
    :on_singleton_class_node_enter,
    :on_singleton_class_node_leave,
    :on_alias_method_node_enter,
  )
end

def on_alias_method_node_enter(node)

def on_alias_method_node_enter(node)
  new_name_node = node.new_name
  return unless new_name_node.is_a?(Prism::SymbolNode)
  name = new_name_node.value
  return unless name
  create_document_symbol(
    name: name,
    kind: Constant::SymbolKind::METHOD,
    range_location: new_name_node.location,
    selection_range_location: T.must(new_name_node.value_loc),
  )
end

def on_call_node_enter(node)

def on_call_node_enter(node)
  if ATTR_ACCESSORS.include?(node.name)
    handle_attr_accessor(node)
  elsif node.name == :alias_method
    handle_alias_method(node)
  end
end

def on_class_node_enter(node)

def on_class_node_enter(node)
  @response_builder << create_document_symbol(
    name: node.constant_path.location.slice,
    kind: Constant::SymbolKind::CLASS,
    range_location: node.location,
    selection_range_location: node.constant_path.location,
  )
end

def on_class_node_leave(node)

def on_class_node_leave(node)
  @response_builder.pop
end

def on_class_variable_write_node_enter(node)

def on_class_variable_write_node_enter(node)
  create_document_symbol(
    name: node.name.to_s,
    kind: Constant::SymbolKind::VARIABLE,
    range_location: node.name_loc,
    selection_range_location: node.name_loc,
  )
end

def on_constant_path_write_node_enter(node)

def on_constant_path_write_node_enter(node)
  create_document_symbol(
    name: node.target.location.slice,
    kind: Constant::SymbolKind::CONSTANT,
    range_location: node.location,
    selection_range_location: node.target.location,
  )
end

def on_constant_write_node_enter(node)

def on_constant_write_node_enter(node)
  create_document_symbol(
    name: node.name.to_s,
    kind: Constant::SymbolKind::CONSTANT,
    range_location: node.location,
    selection_range_location: node.name_loc,
  )
end

def on_def_node_enter(node)

def on_def_node_enter(node)
  receiver = node.receiver
  previous_symbol = @response_builder.last
  if receiver.is_a?(Prism::SelfNode)
    name = "self.#{node.name}"
    kind = Constant::SymbolKind::FUNCTION
  elsif previous_symbol.is_a?(Interface::DocumentSymbol) && previous_symbol.name.start_with?("<<")
    name = node.name.to_s
    kind = Constant::SymbolKind::FUNCTION
  else
    name = node.name.to_s
    kind = name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
  end
  symbol = create_document_symbol(
    name: name,
    kind: kind,
    range_location: node.location,
    selection_range_location: node.name_loc,
  )
  @response_builder << symbol
end

def on_def_node_leave(node)

def on_def_node_leave(node)
  @response_builder.pop
end

def on_instance_variable_write_node_enter(node)

def on_instance_variable_write_node_enter(node)
  create_document_symbol(
    name: node.name.to_s,
    kind: Constant::SymbolKind::VARIABLE,
    range_location: node.name_loc,
    selection_range_location: node.name_loc,
  )
end

def on_module_node_enter(node)

def on_module_node_enter(node)
  @response_builder << create_document_symbol(
    name: node.constant_path.location.slice,
    kind: Constant::SymbolKind::MODULE,
    range_location: node.location,
    selection_range_location: node.constant_path.location,
  )
end

def on_module_node_leave(node)

def on_module_node_leave(node)
  @response_builder.pop
end

def on_singleton_class_node_enter(node)

def on_singleton_class_node_enter(node)
  expression = node.expression
  @response_builder << create_document_symbol(
    name: "<< #{expression.slice}",
    kind: Constant::SymbolKind::NAMESPACE,
    range_location: node.location,
    selection_range_location: expression.location,
  )
end

def on_singleton_class_node_leave(node)

def on_singleton_class_node_leave(node)
  @response_builder.pop
end