<commit_before>﻿using Microsoft.Extensions.Logging;
using NetFusion.Rest.Client.Resources;
using NetFusion.Rest.Client.Settings;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

namespace NetFusion.Rest.Client.Core
{
    /// <summary>
    /// Client used to make HTTP requests.  
    /// </summary>
    public class RequestClient : IRequestClient
    {
        private readonly HttpClient _httpClient;
        private readonly ILogger _logger;
        private string _correlationHeaderName;
        private readonly IDictionary<string, IMediaTypeSerializer> _mediaTypeSerializers;
        private readonly IRequestSettings _defaultRequestSettings;

        private IServiceEntryApiProvider _serviceApiProvider;
        private Action<IRequestSettings> _eachRequestAction;

        /// <summary>
        /// Initializes an instance of the client with its associated HttpClient delegated to 
        /// for making network requests.
        /// </summary>
        /// <param name="httpClient">Reference to a HttpClient instance.</param>
        /// <param name="logger">The logger to use for log messages.</param>
        /// <param name="contentSerializers">Dictionary of serializers keyed by media-type.</param>
        /// <param name="requestSettings">The default request settings to be used for each request.</param>
        public RequestClient(HttpClient httpClient, 
            ILogger logger,
            IDictionary<string, IMediaTypeSerializer> contentSerializers, 
            IRequestSettings requestSettings)
        {
            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient), 
                "HTTP Client cannot be null.");

            _logger = logger ?? throw new ArgumentNullException(nameof(httpClient), 
                "Logger cannot be null.");

            _mediaTypeSerializers = contentSerializers ?? throw new ArgumentNullException(nameof(contentSerializers),
                "HTTP Context Serializers cannot be null.");

            _defaultRequestSettings = requestSettings ?? throw new ArgumentNullException(nameof(requestSettings),
                "Default Request Settings cannot be null.");
        }

        public Task<HalEntryPointResource> GetApiEntry()
        {
            return _serviceApiProvider.GetEntryPointResource();
        }

        // Called by builder when creating client...
        // ---------------------------------------------
        internal void SetApiServiceProvider(IServiceEntryApiProvider provider)
        {
            _serviceApiProvider = provider ?? throw new ArgumentNullException(nameof(provider));
        }

        internal void SetEachRequestAction(Action<IRequestSettings> config)
        {
            _eachRequestAction = config ?? throw new ArgumentNullException(nameof(config));
        }

        internal void AddCorrelationId(string headerName)
        {
            if (string.IsNullOrWhiteSpace(headerName))
                throw new ArgumentException("Correlation header name not specified.", nameof(headerName));

            _correlationHeaderName = headerName;
        }

        // -----

		public Task<ApiResponse> SendAsync(ApiRequest request,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (request == null) throw new ArgumentNullException(nameof(request),
                "Request cannot be null.");

            return SendRequest(request, cancellationToken);
        }

		public Task<ApiResponse<TContent>> SendAsync<TContent>(ApiRequest request,
            CancellationToken cancellationToken = default(CancellationToken))
            where TContent : class
        {
            if (request == null) throw new ArgumentNullException(nameof(request),
                "Request cannot be null.");

            return SendRequest<TContent>(request, cancellationToken);
        }
        
        public Task<ApiResponse> SendAsync(ApiRequest request, Type contentType, 
            CancellationToken cancellationToken)
        {
            if (request == null) throw new ArgumentNullException(nameof(request));
            if (contentType == null) throw new ArgumentNullException(nameof(contentType));

            return SendRequest(request, contentType, cancellationToken);
        }

        private async Task<ApiResponse> SendRequest(ApiRequest request, CancellationToken cancellationToken)
        {
            HttpRequestMessage requestMsg = await CreateRequestMessage(request);
            LogRequest(requestMsg);
            
            HttpResponseMessage responseMsg = await _httpClient.SendAsync(requestMsg, cancellationToken);

            var response = new ApiResponse(requestMsg, responseMsg);
            LogResponse(response);

            return response;
        }

        private async Task<ApiResponse<TContent>> SendRequest<TContent>(ApiRequest request,  CancellationToken cancellationToken)
            where TContent : class
        {
            HttpRequestMessage requestMsg = await CreateRequestMessage(request);
            LogRequest(requestMsg);
            
            TContent resource = null;
            HttpResponseMessage responseMsg = await _httpClient.SendAsync(requestMsg, cancellationToken);
         
            if (responseMsg.IsSuccessStatusCode && responseMsg.Content != null)
            {
                resource = DeserializeResource<TContent>(responseMsg, await responseMsg.Content.ReadAsStreamAsync());
            }

            var response = new ApiResponse<TContent>(requestMsg, responseMsg, resource);
            LogResponse(response);

            return response;
        }
        
        private async Task<ApiResponse> SendRequest(ApiRequest request, Type contentType, 
            CancellationToken cancellationToken)
        {
            HttpRequestMessage requestMsg = await CreateRequestMessage(request);

            LogRequest(requestMsg);
            HttpResponseMessage responseMsg = await _httpClient.SendAsync(requestMsg, cancellationToken);

            object resource = null;
            if (responseMsg.IsSuccessStatusCode && responseMsg.Content != null)
            {
                resource = DeserializeResource(responseMsg, 
                    await responseMsg.Content.ReadAsStreamAsync(), 
                    contentType);
            }

            var response = new ApiResponse(requestMsg, responseMsg, resource);
            LogResponse(response);

            return response;
        }

        private void LogRequest(HttpRequestMessage requestMsg)
        {
            _logger.LogDebug("Sending request to: {uri} for method: {method})", requestMsg.RequestUri, requestMsg.Method);
            _logger.LogTrace("Request Message: {request}", JsonConvert.SerializeObject(requestMsg, Formatting.Indented));
        }

        private void LogResponse(ApiResponse response)<commit_msg>Non-important change.  Fixed typo in log message.<commit_after>﻿using Microsoft.Extensions.Logging;
using NetFusion.Rest.Client.Resources;
using NetFusion.Rest.Client.Settings;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

namespace NetFusion.Rest.Client.Core
{
    /// <summary>
    /// Client used to make HTTP requests.  
    /// </summary>
    public class RequestClient : IRequestClient
    {
        private readonly HttpClient _httpClient;
        private readonly ILogger _logger;
        private string _correlationHeaderName;
        private readonly IDictionary<string, IMediaTypeSerializer> _mediaTypeSerializers;
        private readonly IRequestSettings _defaultRequestSettings;

        private IServiceEntryApiProvider _serviceApiProvider;
        private Action<IRequestSettings> _eachRequestAction;

        /// <summary>
        /// Initializes an instance of the client with its associated HttpClient delegated to 
        /// for making network requests.
        /// </summary>
        /// <param name="httpClient">Reference to a HttpClient instance.</param>
        /// <param name="logger">The logger to use for log messages.</param>
        /// <param name="contentSerializers">Dictionary of serializers keyed by media-type.</param>
        /// <param name="requestSettings">The default request settings to be used for each request.</param>
        public RequestClient(HttpClient httpClient, 
            ILogger logger,
            IDictionary<string, IMediaTypeSerializer> contentSerializers, 
            IRequestSettings requestSettings)
        {
            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient), 
                "HTTP Client cannot be null.");

            _logger = logger ?? throw new ArgumentNullException(nameof(httpClient), 
                "Logger cannot be null.");

            _mediaTypeSerializers = contentSerializers ?? throw new ArgumentNullException(nameof(contentSerializers),
                "HTTP Context Serializers cannot be null.");

            _defaultRequestSettings = requestSettings ?? throw new ArgumentNullException(nameof(requestSettings),
                "Default Request Settings cannot be null.");
        }

        public Task<HalEntryPointResource> GetApiEntry()
        {
            return _serviceApiProvider.GetEntryPointResource();
        }

        // Called by builder when creating client...
        // ---------------------------------------------
        internal void SetApiServiceProvider(IServiceEntryApiProvider provider)
        {
            _serviceApiProvider = provider ?? throw new ArgumentNullException(nameof(provider));
        }

        internal void SetEachRequestAction(Action<IRequestSettings> config)
        {
            _eachRequestAction = config ?? throw new ArgumentNullException(nameof(config));
        }

        internal void AddCorrelationId(string headerName)
        {
            if (string.IsNullOrWhiteSpace(headerName))
                throw new ArgumentException("Correlation header name not specified.", nameof(headerName));

            _correlationHeaderName = headerName;
        }

        // -----

		public Task<ApiResponse> SendAsync(ApiRequest request,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (request == null) throw new ArgumentNullException(nameof(request),
                "Request cannot be null.");

            return SendRequest(request, cancellationToken);
        }

		public Task<ApiResponse<TContent>> SendAsync<TContent>(ApiRequest request,
            CancellationToken cancellationToken = default(CancellationToken))
            where TContent : class
        {
            if (request == null) throw new ArgumentNullException(nameof(request),
                "Request cannot be null.");

            return SendRequest<TContent>(request, cancellationToken);
        }
        
        public Task<ApiResponse> SendAsync(ApiRequest request, Type contentType, 
            CancellationToken cancellationToken)
        {
            if (request == null) throw new ArgumentNullException(nameof(request));
            if (contentType == null) throw new ArgumentNullException(nameof(contentType));

            return SendRequest(request, contentType, cancellationToken);
        }

        private async Task<ApiResponse> SendRequest(ApiRequest request, CancellationToken cancellationToken)
        {
            HttpRequestMessage requestMsg = await CreateRequestMessage(request);
            LogRequest(requestMsg);
            
            HttpResponseMessage responseMsg = await _httpClient.SendAsync(requestMsg, cancellationToken);

            var response = new ApiResponse(requestMsg, responseMsg);
            LogResponse(response);

            return response;
        }

        private async Task<ApiResponse<TContent>> SendRequest<TContent>(ApiRequest request,  CancellationToken cancellationToken)
            where TContent : class
        {
            HttpRequestMessage requestMsg = await CreateRequestMessage(request);
            LogRequest(requestMsg);
            
            TContent resource = null;
            HttpResponseMessage responseMsg = await _httpClient.SendAsync(requestMsg, cancellationToken);
         
            if (responseMsg.IsSuccessStatusCode && responseMsg.Content != null)
            {
                resource = DeserializeResource<TContent>(responseMsg, await responseMsg.Content.ReadAsStreamAsync());
            }

            var response = new ApiResponse<TContent>(requestMsg, responseMsg, resource);
            LogResponse(response);

            return response;
        }
        
        private async Task<ApiResponse> SendRequest(ApiRequest request, Type contentType, 
            CancellationToken cancellationToken)
        {
            HttpRequestMessage requestMsg = await CreateRequestMessage(request);

            LogRequest(requestMsg);
            HttpResponseMessage responseMsg = await _httpClient.SendAsync(requestMsg, cancellationToken);

            object resource = null;
            if (responseMsg.IsSuccessStatusCode && responseMsg.Content != null)
            {
                resource = DeserializeResource(responseMsg, 
                    await responseMsg.Content.ReadAsStreamAsync(), 
                    contentType);
            }

            var response = new ApiResponse(requestMsg, responseMsg, resource);
            LogResponse(response);

            return response;
        }

        private void LogRequest(HttpRequestMessage requestMsg)
        {
            _logger.LogDebug("Sending request to: {uri} for method: {method}.", requestMsg.RequestUri, requestMsg.Method);
            _logger.LogTrace("Request Message: {request}", JsonConvert.SerializeObject(requestMsg, Formatting.Indented));
        }

        private void LogResponse(ApiResponse response)
{'fraction_non_alphanumeric': 0.08273075287111867, 'fraction_numerical': 0.0, 'mean_word_length': 2.5057157057654074, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7319533', 'n_tokens_mistral': 3165, 'n_tokens_neox': 3114, 'n_words': 825}