<commit_before>﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace ArgentPonyWarcraftClient
{
    /// <inheritdoc />
    public partial class WarcraftClient : IWarcraftClient
    {
        private static readonly JsonSerializerOptions s_jsonSerializerOptions;

        private readonly HttpClient _client;
        private readonly string _clientId;
        private readonly string _clientSecret;
        private readonly Region _region;
        private readonly Locale _locale;

        private OAuthAccessToken _token;
        private DateTimeOffset _tokenExpiration;

        /// <summary>
        /// A static constructor for the <see cref="WarcraftClient"/> class.
        /// </summary>
        static WarcraftClient()
        {
            s_jsonSerializerOptions = new JsonSerializerOptions();
            s_jsonSerializerOptions.Converters.Add(new EpochConverter());
            s_jsonSerializerOptions.Converters.Add(new MillisecondTimeSpanConverter());
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="WarcraftClient"/> class.
        /// </summary>
        /// <param name="clientId">The Blizzard OAuth client ID.</param>
        /// <param name="clientSecret">The Blizzard OAuth client secret.</param>
        /// <remarks>
        ///     Defaults the region to US and the locale to "en_US".
        /// </remarks>
        public WarcraftClient(string clientId, string clientSecret) : this(clientId, clientSecret, Region.US, Locale.en_US)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="WarcraftClient"/> class.
        /// </summary>
        /// <param name="clientId">The Blizzard OAuth client ID.</param>
        /// <param name="clientSecret">The Blizzard OAuth client secret.</param>
        /// <param name="region">Specifies the region that the API will retrieve its data from.</param>
        /// <param name="locale">
        ///     Specifies the language that the result will be in. Visit
        ///     https://develop.battle.net/documentation/world-of-warcraft/guides/localization to see a list of available locales.
        /// </param>
        public WarcraftClient(string clientId, string clientSecret, Region region, Locale locale) : this(clientId, clientSecret, region, locale, InternalHttpClient.Instance)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="WarcraftClient"/> class.
        /// </summary>
        /// <param name="clientId">The Blizzard OAuth client ID.</param>
        /// <param name="clientSecret">The Blizzard OAuth client secret.</param>
        /// <param name="region">Specifies the region that the API will retrieve its data from.</param>
        /// <param name="locale">
        ///     Specifies the language that the result will be in. Visit
        ///     https://develop.battle.net/documentation/world-of-warcraft/guides/localization to see a list of available locales.
        /// </param>
        /// <param name="client">The <see cref="HttpClient"/> that communicates with Blizzard.</param>
        public WarcraftClient(string clientId, string clientSecret, Region region, Locale locale, HttpClient client)
        {
            _client = client ?? throw new ArgumentNullException(nameof(client));
            _clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
            _clientSecret = clientSecret ?? throw new ArgumentNullException(nameof(clientSecret));

            if (!locale.IsSupportedInRegion(region))
            {
                throw new ArgumentException("The locale selected is not supported by the selected region.");
            }

            _region = region;
            _locale = locale;
        }

        /// <summary>
        /// The Blizzard OAuth client ID.
        /// </summary>
        internal string ClientId => _clientId;

        /// <summary>
        /// The Blizzard OAuth client secret.
        /// </summary>
        internal string ClientSecret => _clientSecret;

        /// <summary>
        /// The language that results will be in.
        /// </summary>
        internal Locale Locale => _locale;

        /// <summary>
        /// The region the API will retrieve data from.
        /// </summary>
        internal Region Region => _region;

        /// <summary>
        /// The <see cref="HttpClient"/> instance handling requests.
        /// </summary>
        internal HttpClient Client => _client;

        /// <summary>
        ///     Retrieve an item of type <typeparamref name="T"/> from the Blizzard World of Warcraft Game Data or Profile API.
        /// </summary>
        /// <typeparam name="T">
        ///     The return type.
        /// </typeparam>
        /// <param name="region">The region from which to request a token.</param>
        /// <param name="requestUri">
        ///     The URI the request is sent to.
        /// </param>
        /// <returns>
        ///     The JSON response, deserialized to an object of type <typeparamref name="T"/>.
        /// </returns>
        private async Task<RequestResult<T>> GetAsync<T>(Region region, string requestUri)
        {
            // Acquire a new OAuth token if we don't have one. Get a new one if it's expired.
            if (_token == null || DateTimeOffset.UtcNow >= _tokenExpiration)
            {
                _token = await GetOAuthTokenAsync(region).ConfigureAwait(false);
                _tokenExpiration = DateTimeOffset.UtcNow.AddSeconds(_token.ExpiresIn).AddSeconds(-30);
            }

            return await GetAsync<T>(requestUri, _token.AccessToken);
        }

        /// <summary>
        ///     Retrieve an item of type <typeparamref name="T"/> from the Blizzard World of Warcraft Game Data or Profile API.
        /// </summary>
        /// <typeparam name="T">
        ///     The return type.
        /// </typeparam>
        /// <param name="region">The region from which to request a token.</param>
        /// <param name="requestUri">
        ///     The URI the request is sent to.
        /// </param>
        /// <param name="accessToken">
        ///     The OAuth access token.<commit_msg>Removed old param element from /// docs<commit_after>﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace ArgentPonyWarcraftClient
{
    /// <inheritdoc />
    public partial class WarcraftClient : IWarcraftClient
    {
        private static readonly JsonSerializerOptions s_jsonSerializerOptions;

        private readonly HttpClient _client;
        private readonly string _clientId;
        private readonly string _clientSecret;
        private readonly Region _region;
        private readonly Locale _locale;

        private OAuthAccessToken _token;
        private DateTimeOffset _tokenExpiration;

        /// <summary>
        /// A static constructor for the <see cref="WarcraftClient"/> class.
        /// </summary>
        static WarcraftClient()
        {
            s_jsonSerializerOptions = new JsonSerializerOptions();
            s_jsonSerializerOptions.Converters.Add(new EpochConverter());
            s_jsonSerializerOptions.Converters.Add(new MillisecondTimeSpanConverter());
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="WarcraftClient"/> class.
        /// </summary>
        /// <param name="clientId">The Blizzard OAuth client ID.</param>
        /// <param name="clientSecret">The Blizzard OAuth client secret.</param>
        /// <remarks>
        ///     Defaults the region to US and the locale to "en_US".
        /// </remarks>
        public WarcraftClient(string clientId, string clientSecret) : this(clientId, clientSecret, Region.US, Locale.en_US)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="WarcraftClient"/> class.
        /// </summary>
        /// <param name="clientId">The Blizzard OAuth client ID.</param>
        /// <param name="clientSecret">The Blizzard OAuth client secret.</param>
        /// <param name="region">Specifies the region that the API will retrieve its data from.</param>
        /// <param name="locale">
        ///     Specifies the language that the result will be in. Visit
        ///     https://develop.battle.net/documentation/world-of-warcraft/guides/localization to see a list of available locales.
        /// </param>
        public WarcraftClient(string clientId, string clientSecret, Region region, Locale locale) : this(clientId, clientSecret, region, locale, InternalHttpClient.Instance)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="WarcraftClient"/> class.
        /// </summary>
        /// <param name="clientId">The Blizzard OAuth client ID.</param>
        /// <param name="clientSecret">The Blizzard OAuth client secret.</param>
        /// <param name="region">Specifies the region that the API will retrieve its data from.</param>
        /// <param name="locale">
        ///     Specifies the language that the result will be in. Visit
        ///     https://develop.battle.net/documentation/world-of-warcraft/guides/localization to see a list of available locales.
        /// </param>
        /// <param name="client">The <see cref="HttpClient"/> that communicates with Blizzard.</param>
        public WarcraftClient(string clientId, string clientSecret, Region region, Locale locale, HttpClient client)
        {
            _client = client ?? throw new ArgumentNullException(nameof(client));
            _clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
            _clientSecret = clientSecret ?? throw new ArgumentNullException(nameof(clientSecret));

            if (!locale.IsSupportedInRegion(region))
            {
                throw new ArgumentException("The locale selected is not supported by the selected region.");
            }

            _region = region;
            _locale = locale;
        }

        /// <summary>
        /// The Blizzard OAuth client ID.
        /// </summary>
        internal string ClientId => _clientId;

        /// <summary>
        /// The Blizzard OAuth client secret.
        /// </summary>
        internal string ClientSecret => _clientSecret;

        /// <summary>
        /// The language that results will be in.
        /// </summary>
        internal Locale Locale => _locale;

        /// <summary>
        /// The region the API will retrieve data from.
        /// </summary>
        internal Region Region => _region;

        /// <summary>
        /// The <see cref="HttpClient"/> instance handling requests.
        /// </summary>
        internal HttpClient Client => _client;

        /// <summary>
        ///     Retrieve an item of type <typeparamref name="T"/> from the Blizzard World of Warcraft Game Data or Profile API.
        /// </summary>
        /// <typeparam name="T">
        ///     The return type.
        /// </typeparam>
        /// <param name="region">The region from which to request a token.</param>
        /// <param name="requestUri">
        ///     The URI the request is sent to.
        /// </param>
        /// <returns>
        ///     The JSON response, deserialized to an object of type <typeparamref name="T"/>.
        /// </returns>
        private async Task<RequestResult<T>> GetAsync<T>(Region region, string requestUri)
        {
            // Acquire a new OAuth token if we don't have one. Get a new one if it's expired.
            if (_token == null || DateTimeOffset.UtcNow >= _tokenExpiration)
            {
                _token = await GetOAuthTokenAsync(region).ConfigureAwait(false);
                _tokenExpiration = DateTimeOffset.UtcNow.AddSeconds(_token.ExpiresIn).AddSeconds(-30);
            }

            return await GetAsync<T>(requestUri, _token.AccessToken);
        }

        /// <summary>
        ///     Retrieve an item of type <typeparamref name="T"/> from the Blizzard World of Warcraft Game Data or Profile API.
        /// </summary>
        /// <typeparam name="T">
        ///     The return type.
        /// </typeparam>
        /// <param name="requestUri">
        ///     The URI the request is sent to.
        /// </param>
        /// <param name="accessToken">
        ///     The OAuth access token.
{'fraction_non_alphanumeric': 0.11692429647245343, 'fraction_numerical': 0.0003170828378913991, 'mean_word_length': 2.024694317909374, 'pattern_counts': {'":': 0, '<': 151, '<?xml version=': 0, '>': 163, 'https://': 4, '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': '4149006', 'n_tokens_mistral': 3196, 'n_tokens_neox': 3156, 'n_words': 999}