# frozen_string_literal: true

module RuboCop
  module Cop
    module Layout
      # Checks whether comments have a leading space after the
      # `#` denoting the start of the comment. The leading space is not
      # required for some RDoc special syntax, like `#++`, `#--`,
      # `#:nodoc`, `=begin`- and `=end` comments, "shebang" directives,
      # or rackup options.
      #
      # @example
      #
      #   # bad
      #   #Some comment
      #
      #   # good
      #   # Some comment
      #
      # @example AllowDoxygenCommentStyle: false (default)
      #
      #   # bad
      #
      #   #**
      #   # Some comment
      #   # Another line of comment
      #   #*
      #
      # @example AllowDoxygenCommentStyle: true
      #
      #   # good
      #
      #   #**
      #   # Some comment
      #   # Another line of comment
      #   #*
      #
      # @example AllowGemfileRubyComment: false (default)
      #
      #   # bad
      #
      #   #ruby=2.7.0
      #   #ruby-gemset=myproject
      #
      # @example AllowGemfileRubyComment: true
      #
      #   # good
      #
      #   #ruby=2.7.0
      #   #ruby-gemset=myproject
      #
      class LeadingCommentSpace < Base
        include RangeHelp
        extend AutoCorrector

        MSG = 'Missing space after `#`.'

        def on_new_investigation
          processed_source.comments.each do |comment|
            next unless /\A#+[^#\s=+-]/.match?(comment.text)
            next if comment.loc.line == 1 && allowed_on_first_line?(comment)
            next if doxygen_comment_style?(comment)
            next if gemfile_ruby_comment?(comment)

            add_offense(comment) do |corrector|
              expr = comment.loc.expression

              corrector.insert_after(hash_mark(expr), ' ')
            end
          end
        end

        private

        def hash_mark(expr)
          range_between(expr.begin_pos, expr.begin_pos + 1)
        end

        def allowed_on_first_line?(comment)
          shebang?(comment) || (rackup_config_file? && rackup_options?(comment))
        end

        def shebang?(comment)
          comment.text.start_with?('#!')
        end

        def rackup_options?(comment)
          comment.text.start_with?('#\\')
        end

        def rackup_config_file?
          File.basename(processed_source.file_path).eql?('config.ru')
        end

        def allow_doxygen_comment?
          cop_config['AllowDoxygenCommentStyle']
        end

        def doxygen_comment_style?(comment)
          allow_doxygen_comment? && comment.text.start_with?('#*')
        end

        def allow_gemfile_ruby_comment?
          cop_config['AllowGemfileRubyComment']
        end

        def gemfile?
          File.basename(processed_source.file_path).eql?('Gemfile')
        end

        def ruby_comment_in_gemfile?(comment)
          gemfile? && comment.text.start_with?('#ruby')
        end

        def gemfile_ruby_comment?(comment)
          allow_gemfile_ruby_comment? && ruby_comment_in_gemfile?(comment)
        end
      end
    end
  end
end
