/// <summary>
        ///     A convenience function that tries to ensure that a given URL is a valid tictail domain. It does this by making a
        ///     HEAD request to the given domain, and returns true if the response contains an X-ShopId header.
        ///     **Warning**: a domain could fake the response header, which would cause this method to return true.
        ///     **Warning**: this method of validation is not officially supported by tictail and could break at any time.
        /// </summary>
        /// <param name="url">The URL of the shop to check.</param>
        /// <returns>A boolean indicating whether the URL is valid.</returns>
        public static async Task <bool> IsValidShopDomainAsync(string url)
        {
            var uri = TictailService.BuildShopUri(url, true);

            using (var client = new HttpClient())
            {
                using (var msg = new HttpRequestMessage(HttpMethod.Head, uri))
                {
                    try
                    {
                        var response = await client.SendAsync(msg);

                        return(response.Headers.Any(h => h.Key == "X-ShopId"));
                    }
                    catch (HttpRequestException)
                    {
                        return(false);
                    }
                }
            }
        }
        /// <summary>
        ///     Builds an authorization URL for tictail OAuth integration.
        /// </summary>
        /// <param name="scopes"></param>
        /// <param name="myTictailUrl">The shop's *.mytictail.com URL.</param>
        /// <param name="tictailApiKey">Your app's public API key.</param>
        /// <param name="redirectUrl"></param>
        /// <param name="state"></param>
        /// <returns>The authorization url.</returns>
        public static Uri BuildAuthorizationUrl(IEnumerable <string> scopes, string myTictailUrl, string tictailApiKey, string redirectUrl, string state = null)
        {
            //Prepare a uri builder for the shop URL
            var builder        = new UriBuilder(TictailService.BuildShopUri(myTictailUrl, false));
            var scopeFormateed = $"{string.Join(",", scopes)}";
            //Build the querystring
            var qs = new List <KeyValuePair <string, string> >
            {
                new KeyValuePair <string, string>("response_type", "code"),
                new KeyValuePair <string, string>("client_id", tictailApiKey),
                new KeyValuePair <string, string>("scope", scopeFormateed),
                new KeyValuePair <string, string>("state", state),
                new KeyValuePair <string, string>("redirect_uri", HttpUtility.UrlEncode(redirectUrl)),
            };



            builder.Path  = "oauth/authorize";
            builder.Query = string.Join("&", qs.Select(s => $"{s.Key}={s.Value}"));

            return(builder.Uri);
        }
        /// <summary>
        ///     Authorizes an application installation, generating an access token for the given shop.
        /// </summary>
        /// <param name="authCode"></param>
        /// <param name="myTictailUrl">
        ///     The store's *.tictail.com URL, which should be a paramter named 'shop' on the request
        ///     querystring.
        /// </param>
        /// <param name="tictailApiKey">Your app's public API key.</param>
        /// <param name="tictailSecretKey">Your app's secret key.</param>
        /// <param name="scopes"></param>
        /// <returns>The authorization result.</returns>
        public static async Task <Root> AuthorizeWithResult(string authCode, string myTictailUrl,
                                                            string tictailApiKey, string tictailSecretKey, IEnumerable <string> scopes)
        {
            var ub = new UriBuilder(TictailService.BuildShopUri(myTictailUrl, false))
            {
                Path = "oauth/token"
            };

            var values = new Dictionary <string, string>
            {
                { "client_id", $"{tictailApiKey}" },
                { "client_secret", $"{tictailSecretKey}" },
                { "code", $"{authCode}" },
                { "grant_type", "authorization_code" },
                { "scope", $"[{string.Join(",", scopes)}]" },
            };

            var content = new FormUrlEncodedContent(values);

            using (var client = new HttpClient())
                using (var msg = new CloneableRequestMessage(ub.Uri, HttpMethod.Post, content))
                {
                    var request       = client.SendAsync(msg);
                    var response      = await request;
                    var rawDataString = await response.Content.ReadAsStringAsync();

                    TictailService.CheckResponseExceptions(response, rawDataString);

                    //var json = JToken.Parse(rawDataString);
                    //var a = new AuthorizationResult(json.Value<string>("access_token"),
                    //    json.Value<string>("scope").Split(','), json.Value<TictailStore>("store"));
                    var json = JsonConvert.DeserializeObject <Root>(rawDataString);
                    //return new AuthorizationResult(json.Value<string>("access_token"),
                    //    json.Value<string>("scope").Split(','), json.Value<TictailStore>("store"));
                    return(json);
                }
        }