# frozen_string_literal: true

module RuboCop
  module Cop
    module Style
      # Check for parentheses around stabby lambda arguments.
      # There are two different styles. Defaults to `require_parentheses`.
      #
      # @example
      #   # require_parentheses - bad
      #   ->a,b,c { a + b + c }
      #
      #   # require_parentheses - good
      #   ->(a,b,c) { a + b + c}
      #
      #   # require_no_parentheses - bad
      #   ->(a,b,c) { a + b + c }
      #
      #   # require_no_parentheses - good
      #   ->a,b,c { a + b + c}
      class StabbyLambdaParentheses < Cop
        include ConfigurableEnforcedStyle

        MSG_REQUIRE = 'Wrap stabby lambda arguments with parentheses.'.freeze
        MSG_NO_REQUIRE = 'Do not wrap stabby lambda arguments ' \
                         'with parentheses.'.freeze
        ARROW = '->'.freeze

        def on_send(node)
          return unless stabby_lambda_with_args?(node)
          return unless redundant_parentheses?(node) ||
                        missing_parentheses?(node)

          add_offense(node.parent.arguments)
        end

        def autocorrect(node)
          if style == :require_parentheses
            missing_parentheses_corrector(node)
          elsif style == :require_no_parentheses
            unwanted_parentheses_corrector(node)
          end
        end

        private

        def missing_parentheses?(node)
          style == :require_parentheses && !parentheses?(node)
        end

        def redundant_parentheses?(node)
          style == :require_no_parentheses && parentheses?(node)
        end

        def message(_node)
          style == :require_parentheses ? MSG_REQUIRE : MSG_NO_REQUIRE
        end

        def missing_parentheses_corrector(node)
          lambda do |corrector|
            args_loc = node.parent.arguments.source_range

            corrector.insert_before(args_loc, '(')
            corrector.insert_after(args_loc, ')')
          end
        end

        def unwanted_parentheses_corrector(node)
          lambda do |corrector|
            args_loc = node.parent.arguments.loc

            corrector.replace(args_loc.begin, '')
            corrector.remove(args_loc.end)
          end
        end

        def stabby_lambda_with_args?(node)
          node.command?(:lambda) && arrow_form?(node) && node.parent.arguments?
        end

        def arrow_form?(node)
          node.loc.selector.source == ARROW
        end

        def parentheses?(node)
          node.parent.arguments.loc.begin
        end
      end
    end
  end
end
