module Tapioca::RBIHelper

def as_nilable_type(type)

: (String type) -> String
def as_nilable_type(type)
  if type.start_with?("T.nilable(", "::T.nilable(") || type == "T.untyped" || type == "::T.untyped"
    type
  else
    "T.nilable(#{type})"
  end
end

def as_non_nilable_type(type)

: (String type) -> String
def as_non_nilable_type(type)
  if type.match(/\A(?:::)?T.nilable\((.+)\)\z/)
    T.must(::Regexp.last_match(1))
  else
    type
  end
end

def create_block_param(name, type:)

: (String name, type: String) -> RBI::TypedParam
def create_block_param(name, type:)
  create_typed_param(RBI::BlockParam.new(name), type)
end

def create_kw_opt_param(name, type:, default:)

: (String name, type: String, default: String) -> RBI::TypedParam
def create_kw_opt_param(name, type:, default:)
  create_typed_param(RBI::KwOptParam.new(name, default), type)
end

def create_kw_param(name, type:)

: (String name, type: String) -> RBI::TypedParam
def create_kw_param(name, type:)
  create_typed_param(RBI::KwParam.new(name), type)
end

def create_kw_rest_param(name, type:)

: (String name, type: String) -> RBI::TypedParam
def create_kw_rest_param(name, type:)
  create_typed_param(RBI::KwRestParam.new(name), type)
end

def create_opt_param(name, type:, default:)

: (String name, type: String, default: String) -> RBI::TypedParam
def create_opt_param(name, type:, default:)
  create_typed_param(RBI::OptParam.new(name, default), type)
end

def create_param(name, type:)

: (String name, type: String) -> RBI::TypedParam
def create_param(name, type:)
  create_typed_param(RBI::ReqParam.new(name), type)
end

def create_rest_param(name, type:)

: (String name, type: String) -> RBI::TypedParam
def create_rest_param(name, type:)
  create_typed_param(RBI::RestParam.new(name), type)
end

def create_typed_param(param, type)

: (RBI::Param param, String type) -> RBI::TypedParam
def create_typed_param(param, type)
  RBI::TypedParam.new(param: param, type: sanitize_signature_types(type))
end

def sanitize_signature_types(sig_string)

: (String sig_string) -> String
def sanitize_signature_types(sig_string)
  sig_string
    .gsub(".returns(<VOID>)", ".void")
    .gsub("<VOID>", "void")
    .gsub("<NOT-TYPED>", "T.untyped")
    .gsub(".params()", "")
end

def serialize_type_variable(type, variance, fixed, upper, lower)

: (String type, Symbol variance, String? fixed, String? upper, String? lower) -> String
def serialize_type_variable(type, variance, fixed, upper, lower)
  variance = nil if variance == :invariant
  block = []
  block << "fixed: #{fixed}" if fixed
  block << "lower: #{lower}" if lower
  block << "upper: #{upper}" if upper
  parameters = []
  parameters << ":#{variance}" if variance
  serialized = type.dup
  serialized << "(#{parameters.join(", ")})" unless parameters.empty?
  serialized << " { { #{block.join(", ")} } }" unless block.empty?
  serialized
end

def valid_method_name?(name)

: (String name) -> bool
def valid_method_name?(name)
  Prism.parse_success?("def self.#{name}(a); end")
end

def valid_parameter_name?(name)

: (String name) -> bool
def valid_parameter_name?(name)
  Prism.parse_success?("def sentinel_method_name(#{name}:); end")
end