# frozen_string_literal: true

module Preval
  class Visitors
    class AttrAccessor < Visitor
      def on_def(node)
        # auto create attr_readers
        if node.type_match?(:@ident, :params, :bodystmt) &&
           # def foo; @foo; end
           node[1].body.none? &&
           # there are no params to this method
           node[2, 0].type_match?(:stmts_new, :var_ref) &&
           # there is only one statement in the body and its a var reference
           node[2, 0, 1, 0].is?(:@ivar) &&
           # the var reference is referencing an instance variable
           node[0].body == node[2, 0, 1, 0].body[1..-1]
           # the name of the variable matches the name of the method

          ast = Parser.parse("attr_reader :#{node[0].body}")
          node.update(:stmts_add, ast.body[0].body)
        end

        # auto create attr_writers
        if node.type_match?(:@ident, :paren, :bodystmt) &&
           # def foo=(value); @foo = value; end
           node[0].body.end_with?('=') &&
           # this is a setter method
           node[1, 0, 0].length == 1 &&
           # there is exactly one required param
           node[1, 0].body[1..-1].none? &&
           # there are no other params
           (
             node[2, 0].type_match?(:stmts_new, :assign) || (
               node[2, 0, 0].type_match?(:stmts_new, :void_stmt) &&
               node[2, 0].type_match?(:stmts_add, :assign)
             )
           ) &&
           # there is only one statement in the body and it's an assignment
           node[2, 0, 1].type_match?(:var_field, :var_ref) &&
           # assigning a variable
           node[2, 0, 1, 0, 0].is?(:@ivar) &&
           # assigning to an instance variable
           node[0].body[0..-2] == node[2, 0, 1, 0, 0].body[1..-1] &&
           # variable name matches the method name
           node[1, 0, 0][0].body == node[2, 0, 1, 1, 0].body
           # assignment variable matches the argument name

          ast = Parser.parse("attr_writer :#{node[0].body[0..-2]}")
          node.update(:stmts_add, ast.body[0].body)
        end
      end
    end
  end
end
