class Bundler::PubGrub::FailureWriter

def visit(incompatibility, conclusion: false)

def visit(incompatibility, conclusion: false)
  raise unless incompatibility.conflict?
  numbered = conclusion || @derivations[incompatibility] > 1;
  conjunction = conclusion || incompatibility == @root ? "So," : "And"
  cause = incompatibility.cause
  if cause.conflict.conflict? && cause.other.conflict?
    conflict_line = @line_numbers[cause.conflict]
    other_line = @line_numbers[cause.other]
    if conflict_line && other_line
      write_line(
        incompatibility,
        "Because #{cause.conflict} (#{conflict_line})\nand #{cause.other} (#{other_line}),\n#{incompatibility}.",
        numbered: numbered
      )
    elsif conflict_line || other_line
      with_line    = conflict_line ? cause.conflict : cause.other
      without_line = conflict_line ? cause.other : cause.conflict
      line = @line_numbers[with_line]
      visit(without_line);
      write_line(
        incompatibility,
        "#{conjunction} because #{with_line} (#{line}),\n#{incompatibility}.",
        numbered: numbered
      )
    else
      single_line_conflict = single_line?(cause.conflict.cause)
      single_line_other    = single_line?(cause.other.cause)
      if single_line_conflict || single_line_other
        first  = single_line_other ? cause.conflict : cause.other
        second = single_line_other ? cause.other : cause.conflict
        visit(first)
        visit(second)
        write_line(
          incompatibility,
          "Thus, #{incompatibility}.",
          numbered: numbered
        )
      else
        visit(cause.conflict, conclusion: true)
        @lines << ["", nil]
        visit(cause.other)
        write_line(
          incompatibility,
          "#{conjunction} because #{cause.conflict} (#{@line_numbers[cause.conflict]}),\n#{incompatibility}.",
          numbered: numbered
        )
      end
    end
  elsif cause.conflict.conflict? || cause.other.conflict?
    derived = cause.conflict.conflict? ? cause.conflict : cause.other
    ext     = cause.conflict.conflict? ? cause.other : cause.conflict
    derived_line = @line_numbers[derived]
    if derived_line
      write_line(
        incompatibility,
        "Because #{ext}\nand #{derived} (#{derived_line}),\n#{incompatibility}.",
        numbered: numbered
      )
    elsif collapsible?(derived)
      derived_cause = derived.cause
      if derived_cause.conflict.conflict?
        collapsed_derived = derived_cause.conflict
        collapsed_ext = derived_cause.other
      else
        collapsed_derived = derived_cause.other
        collapsed_ext = derived_cause.conflict
      end
      visit(collapsed_derived)
      write_line(
        incompatibility,
        "#{conjunction} because #{collapsed_ext}\nand #{ext},\n#{incompatibility}.",
        numbered: numbered
      )
    else
      visit(derived)
      write_line(
        incompatibility,
        "#{conjunction} because #{ext},\n#{incompatibility}.",
        numbered: numbered
      )
    end
  else
    write_line(
      incompatibility,
      "Because #{cause.conflict}\nand #{cause.other},\n#{incompatibility}.",
      numbered: numbered
    )
  end
end