module Roda::RodaPlugins::ReeRoutes::ClassMethods

def build_routes_proc

def build_routes_proc
  list = []
  context = self
  return list if @ree_routes.nil? || @ree_routes.empty?
  if context.opts[:ree_routes_swagger_url]
    list << Proc.new do |r|
      r.get context.opts[:ree_routes_swagger_url] do
        r.json do
          response.status = 200
          ReeJson::ToJson.new.call(context.opts[:ree_routes_swagger])
        end
      end
    end
  end
  routing_tree = ReeRoda::BuildRoutingTree.new.call(@ree_routes)
  route_tree_proc = build_traverse_tree_proc(routing_tree, context)
  list << Proc.new do |r|
    r.instance_exec(r, &route_tree_proc)
  end
  opts[:ree_routes_proc] = list
end

def build_traverse_tree_proc(tree, context)

def build_traverse_tree_proc(tree, context)
  has_arbitrary_param = tree.values[0].start_with?(":")
  route_parts = has_arbitrary_param ? tree.values.map { _1.gsub(":", "") } : tree.values
  procs = []
  child_procs = tree.children.map do |child|
    build_traverse_tree_proc(child, context)
  end
  route_procs = tree.routes.map do |route|
    route_proc(route, context)
  end
  procs << if tree.children.length > 0
    if has_arbitrary_param
      Proc.new do |r|
        r.on String do |param_val|
          route_parts.each do |route_part|
            r.params[route_part] = param_val
          end
          child_procs.each do |child_proc|
            r.instance_exec(r, &child_proc)
          end
          r.is do
            route_procs.each do |route_proc|
              r.instance_exec(r, &route_proc)
            end
            nil
          end
          nil
        end
      end
    else
      Proc.new do |r|
        r.on route_parts[0] do
          child_procs.each do |child_proc|
            r.instance_exec(r, &child_proc)
          end
          r.is do
            route_procs.each do |route_proc|
              r.instance_exec(r, &route_proc)
            end
            nil
          end
          nil
        end
      end
    end
  else
    Proc.new do |r|
      if has_arbitrary_param
        r.is String do |param_val|
          route_parts.each do |route_part|
            r.params[route_part] = param_val
          end
          r.is do
            route_procs.each do |route_proc|
              r.instance_exec(r, &route_proc)
            end
            nil
          end
          nil
        end
      else
        r.is route_parts[0] do
          r.is do
            route_procs.each do |route_proc|
              r.instance_exec(r, &route_proc)
            end
            nil
          end
          nil
        end
      end
    end
  end
  Proc.new do |r|
    procs.each do |proc|
      r.instance_exec(r, &proc)
    end
  end
end

def ree_routes(routes, swagger_title: "", swagger_description: "",

def ree_routes(routes, swagger_title: "", swagger_description: "",
                swagger_version: "", swagger_url: "", api_url: "")
  @ree_routes ||= []
  @ree_routes += routes
  opts[:ree_routes_swagger_title] = swagger_title
  opts[:ree_routes_swagger_description] = swagger_description
  opts[:ree_routes_swagger_version] = swagger_version
  opts[:ree_routes_swagger_url] = swagger_url
  opts[:ree_routes_api_url] = api_url
  opts[:ree_routes_swagger] = ReeRoda::BuildSwaggerFromRoutes.new.call(
    @ree_routes,
    opts[:ree_routes_swagger_title],
    opts[:ree_routes_swagger_description],
    opts[:ree_routes_swagger_version],
    opts[:ree_routes_api_url]
  )
  build_routes_proc
  nil
end

def route_proc(route, context)

def route_proc(route, context)
  Proc.new do |r|
    r.send(route.request_method) do
      if route.override
        r.instance_exec(r, &route.override)
      else
        r.send(route.respond_to) do
          r.env["warden"].authenticate!(scope: route.warden_scope)
          if context.opts[:ree_routes_before]
            r.instance_exec(@_request, route.warden_scope, &r.scope.opts[:ree_routes_before])
          end
          params = r.params
          if r.body
            body = begin
              JSON.parse(r.body.read)
            rescue => e
              {}
            end
            params = params.merge(body)
          end
          not_blank = ReeObject::NotBlank.new
          filtered_params = ReeHash::TransformValues.new.call(params) do |k, v|
            v.is_a?(Array) ? v.select { not_blank.call(_1) } : v
          end
          accessor = r.env["warden"].user(route.warden_scope)
          action_result = get_cached_action(route).call(accessor, filtered_params)
          if route.serializer
            serialized_result = get_cached_serializer(route).serialize(action_result)
          else
            serialized_result = {}
          end
          case route.request_method
          when :post
            r.response.status = 201
            ReeJson::ToJson.new.call(serialized_result)
          when :put, :delete, :patch
            r.response.status = 204
            ""
          else
            r.response.status = 200
            ReeJson::ToJson.new.call(serialized_result)
          end
        end
      end
      nil
    end
  end
end