module RuboCop::Cop::RSpec::ExplicitHelper

def allowed_explicit_matchers

def allowed_explicit_matchers
  cop_config.fetch('AllowedExplicitMatchers', []) + BUILT_IN_MATCHERS
end

def check_explicit(node) # rubocop:disable Metrics/MethodLength

rubocop:disable Metrics/MethodLength
def check_explicit(node) # rubocop:disable Metrics/MethodLength
  predicate_matcher_block?(node) do |actual, matcher|
    add_offense(node, message: message_explicit(matcher)) do |corrector|
      to_node = node.send_node
      corrector_explicit(corrector, to_node, actual, matcher, to_node)
    end
    ignore_node(node.children.first)
    return
  end
  return if part_of_ignored_node?(node)
  predicate_matcher?(node) do |actual, matcher|
    next unless replaceable_matcher?(matcher)
    add_offense(node, message: message_explicit(matcher)) do |corrector|
      next if uncorrectable_matcher?(node, matcher)
      corrector_explicit(corrector, node, actual, matcher, matcher)
    end
  end
end

def corrector_explicit(corrector, to_node, actual, matcher, block_child)

def corrector_explicit(corrector, to_node, actual, matcher, block_child)
  replacement_matcher = replacement_matcher(to_node)
  corrector.replace(matcher, replacement_matcher)
  move_predicate(corrector, actual, matcher, block_child)
  corrector.replace(to_node.loc.selector, 'to')
end

def heredoc_argument?(matcher)

def heredoc_argument?(matcher)
  matcher.arguments.select do |arg|
    arg.type?(:str, :dstr, :xstr)
  end.any?(&:heredoc?)
end

def message_explicit(matcher)

def message_explicit(matcher)
  format(MSG_EXPLICIT,
         predicate_name: to_predicate_method(matcher.method_name),
         matcher_name: matcher.method_name)
end

def move_predicate(corrector, actual, matcher, block_child)

def move_predicate(corrector, actual, matcher, block_child)
  predicate = to_predicate_method(matcher.method_name)
  args = LocationHelp.arguments_with_whitespace(matcher).source
  block_loc = LocationHelp.block_with_whitespace(block_child)
  block = block_loc ? block_loc.source : ''
  corrector.remove(block_loc) if block_loc
  corrector.insert_after(actual, ".#{predicate}" + args + block)
end

def predicate_matcher_name?(name)

def predicate_matcher_name?(name)
  name = name.to_s
  return false if allowed_explicit_matchers.include?(name)
  (name.start_with?('be_', 'have_') && !name.end_with?('?')) ||
    %w[include respond_to].include?(name)
end

def replaceable_matcher?(matcher)

def replaceable_matcher?(matcher)
  case matcher.method_name.to_s
  when 'include'
    matcher.arguments.one?
  else
    true
  end
end

def replacement_matcher(node)

def replacement_matcher(node)
  case [cop_config['Strict'], node.method?(:to)]
  when [true, true]
    'be(true)'
  when [true, false]
    'be(false)'
  when [false, true]
    'be_truthy'
  else
    'be_falsey'
  end
end

def to_predicate_method(matcher)

def to_predicate_method(matcher)
  case matcher = matcher.to_s
  when 'be_a', 'be_an', 'be_a_kind_of', 'a_kind_of', 'be_kind_of'
    'is_a?'
  when 'be_an_instance_of', 'be_instance_of', 'an_instance_of'
    'instance_of?'
  when 'include'
    'include?'
  when 'respond_to'
    'respond_to?'
  when /\Ahave_(.+)/
    "has_#{Regexp.last_match(1)}?"
  else
    "#{matcher[/\Abe_(.+)/, 1]}?"
  end
end

def uncorrectable_matcher?(node, matcher)

def uncorrectable_matcher?(node, matcher)
  heredoc_argument?(matcher) && !same_line?(node, matcher)
end