module MessageRequest

using URIs, LoggingExtras
using ..IOExtras, ..Messages, ..Parsers, ..Exceptions
using ..Messages, ..Parsers
using ..Strings: HTTPVersion
import ..DEBUG_LEVEL

export messagelayer

# like Messages.mkheaders, but we want to make a copy of user-provided headers
# and avoid double copy when no headers provided (very common)
mkreqheaders(::Nothing, ch) = Header[]
mkreqheaders(headers::Headers, ch) = ch ? copy(headers) : headers
mkreqheaders(h, ch) = mkheaders(h)

"""
    messagelayer(handler) -> handler

Construct a [`Request`](@ref) object from method, url, headers, and body.
Hard-coded as the first layer in the request pipeline.
"""
function messagelayer(handler)
    return function makerequest(method::String, url::URI, headers, body; copyheaders::Bool=true, response_stream=nothing, http_version=HTTPVersion(1, 1), verbose=DEBUG_LEVEL[], kw...)
        req = Request(method, resource(url), mkreqheaders(headers, copyheaders), body; url=url, version=http_version, responsebody=response_stream)
        local resp
        start_time = time()
        try
            # if debugging, enable by wrapping request in custom logger logic
            resp = if verbose > 0
                LoggingExtras.withlevel(Logging.Debug) do
                    handler(req; verbose, response_stream, kw...)
                end
            else
                handler(req; verbose, response_stream, kw...)
            end
        catch e
            if e isa CapturedException
                e = e.ex
            end
            if e isa StatusError
                resp = e.response
            end
            rethrow(e)
        finally
            dur = (time() - start_time) * 1000
            req.context[:total_request_duration_ms] = dur
            if @isdefined(resp) && iserror(resp) && haskey(resp.request.context, :response_body)
                if isbytes(resp.body)
                    resp.body = resp.request.context[:response_body]
                else
                    write(resp.body, resp.request.context[:response_body])
                end
            end
        end
    end
end

end # module MessageRequest
