private async Task <ProcoreResponse <TResponse> > ReadResponse <TResponse>(ProcoreRequest <TResponse> request, HttpResponseMessage httpResponse)
        {
            using Stream stream = await httpResponse.Content.ReadAsStreamAsync();

            using StreamReader sr   = new StreamReader(stream);
            using JsonTextReader jr = new JsonTextReader(sr);

            JsonSerializer jsonSerializer = new JsonSerializer();

            if (!httpResponse.IsSuccessStatusCode)
            {
                string error = await sr.ReadToEndAsync();

                if (httpResponse.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
                {
                    int            unixTimeUntilRefresh = int.Parse(httpResponse.Headers.GetValues("X-Rate-Limit-Reset".ToLower()).First());
                    DateTimeOffset refreshDate          = DateTimeOffset.FromUnixTimeSeconds(unixTimeUntilRefresh);
                    DateTimeOffset currentDate          = DateTimeOffset.UtcNow;

                    TimeSpan timeDifference     = refreshDate - currentDate;
                    int      millisecondsToWait = (int)Math.Max(timeDifference.TotalMilliseconds, 0);

                    await Task.Delay(millisecondsToWait);

                    return(await this.GetResponseAsync <TResponse>(request));
                }

                throw new ProcoreApiException(httpResponse.ReasonPhrase, error, httpResponse.StatusCode);
            }

            // Extract the last page from the response headers
            int lastPage = 1;

            if (httpResponse.Headers.TryGetValues("total", out IEnumerable <string> totalValues))
            {
                string totalString = totalValues.First();
                int    total       = int.Parse(totalString);
                float  totalPages  = (float)total / Constants.MaxResultsPerPage;

                lastPage = Math.Max((int)Math.Ceiling(totalPages), 1);
            }

            TResponse result = jsonSerializer.Deserialize <TResponse>(jr);

            ProcoreResponse <TResponse> procoreResponse = new ProcoreResponse <TResponse>(this)
            {
                Result     = result,
                Request    = request,
                IsLastPage = request.Page == lastPage
            };

            return(procoreResponse);
        }
        public async Task <ProcoreResponse <TResponse> > GetResponseAsync <TResponse>(ProcoreRequest <TResponse> request)
        {
            await this.Authenticate();

            var queryParams = this.querySegmentFactory.Create(request);
            var query       = $"{request.Resource.TrimStart('/')}?{string.Join("&", queryParams)}";

            HttpResponseMessage httpResponse;

            if (request.HttpMethod == HttpMethod.Get)
            {
                httpResponse = await this.httpClient.GetAsync(query);
            }
            else if (request.HttpMethod == HttpMethod.Post)
            {
                httpResponse = await this.httpClient.PostAsync(query, new StringContent(request.Body));
            }
            else if (request.HttpMethod == HttpMethod.Patch)
            {
                httpResponse = await this.httpClient.PatchAsync(query, new StringContent(request.Body));
            }
            else
            {
                throw new NotImplementedException();
            }

            return(await this.ReadResponse <TResponse>(request, httpResponse));
        }