private async Task <SpotifyUserToken> GetDbToken(string synthbotUserId)
        {
            var spotifyUserId = await _db.UserLogins
                                .Where(ul => ul.LoginProvider == "Spotify")
                                .Select(ul => ul.ProviderKey)
                                .FirstOrDefaultAsync();

            if (string.IsNullOrEmpty(spotifyUserId))
            {
                return(null);
            }

            var userTokensQueryable = _db.UserTokens.Where(ut => ut.UserId == synthbotUserId && ut.LoginProvider == "Spotify");

            var spotifyToken = SpotifyToken.FromUserTokens(userTokensQueryable);

            spotifyToken.Validate();

            var userToken = new SpotifyUserToken()
            {
                SynthbotUserId           = synthbotUserId,
                SpotifyUserId            = spotifyUserId,
                SpotifyAccessToken       = spotifyToken.AccessToken,
                SpotifyAccessTokenExpiry = spotifyToken.ExpiresAt,
                SpotifyRefreshToken      = spotifyToken.RefreshToken
            };

            return(userToken);
        }
        private async Task UpdateDbAsync(SpotifyUserToken userToken)
        {
            await _dbSignal.WaitAsync();

            var accessTokenRecord = await _db.UserTokens
                                    .FirstOrDefaultAsync(t => t.UserId == userToken.SynthbotUserId && t.Name == "access_token");

            if (accessTokenRecord != null)
            {
                accessTokenRecord.Value = userToken.SpotifyAccessToken;
                _db.Update(accessTokenRecord);
            }
            else
            {
                accessTokenRecord = new IdentityUserToken <string>()
                {
                    LoginProvider = "Spotify",
                    Name          = "access_token",
                    UserId        = userToken.SynthbotUserId,
                    Value         = userToken.SpotifyAccessToken
                };
                await _db.UserTokens.AddAsync(accessTokenRecord);
            }
            var expiresAtRecord = await _db.UserTokens.FirstOrDefaultAsync(t => t.UserId == userToken.SynthbotUserId && t.Name == "expires_at");

            if (expiresAtRecord != null)
            {
                expiresAtRecord.Value = userToken.SpotifyAccessTokenExpiry.ToString("O");
                _db.Update(expiresAtRecord);
            }
            else
            {
                expiresAtRecord = new IdentityUserToken <string>()
                {
                    LoginProvider = "Spotify",
                    Name          = "expires_at",
                    UserId        = userToken.SynthbotUserId,
                    Value         = userToken.SpotifyAccessTokenExpiry.ToString("O")
                };
                await _db.AddAsync(expiresAtRecord);
            }

            try
            {
                await _db.SaveChangesAsync();
            }
            finally
            {
                _dbSignal.Release();
            }
        }
        public async Task <RefreshAccessTokenResponse> RefreshTokenAsync(SpotifyUserToken userToken)
        {
            var uri = new Uri($"https://accounts.spotify.com/api/token");

            // Create body parameters
            var parameters = new List <KeyValuePair <string, string> >();

            parameters.Add(new KeyValuePair <string, string>("grant_type", "refresh_token"));
            parameters.Add(new KeyValuePair <string, string>("refresh_token", userToken.SpotifyRefreshToken));

            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri)
            {
                Content = new FormUrlEncodedContent(parameters)
            };

            // Create encoded credentials header value
            var sb = new StringBuilder();

            sb.Append(_config["spotify.api.clientid"]);
            sb.Append($":");
            sb.Append(_config["spotify.api.clientsecret"]);
            var encodedCredentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(sb.ToString()));

            // Add authorization header
            request.Headers.Add("Authorization", $"Basic {encodedCredentials}");

            // Send the request
            var result = await _httpClient.SendAsync(request);

            if (result.IsSuccessStatusCode)
            {
                var contentString = await result.Content.ReadAsStringAsync();

                var tokenResponse = JsonConvert.DeserializeObject <SpotifyAccessTokenResponse>(contentString);

                // Set the updated access token on the user token that was passed in
                userToken.SpotifyAccessToken       = tokenResponse.AccessToken;
                userToken.SpotifyAccessTokenExpiry = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresInSeconds);

                // Return token response
                return(RefreshAccessTokenResponse.CreateSuccess());
            }
            else
            {
                return(RefreshAccessTokenResponse
                       .CreateFailure(
                           $"Failed to refresh token. Received error response from Spotify. Status Code: {result.StatusCode}"));
            }
        }
        public async Task <SpotifyUserToken> RefreshToken(SpotifyUserToken userToken, string synthbotUserId)
        {
            _logger.Log(LogLevel.Information, "Refreshing spotify token for user: {synthbotUserId}", synthbotUserId);
            var refreshResponse = await userToken.Refresh(_refreshService);

            if (!refreshResponse.Success)
            {
                _logger.Log(LogLevel.Error, "Token refresh failed for user: {synthbotUserId}", synthbotUserId);
                return(null);
            }

            _logger.Log(LogLevel.Information, "Token refresh successful for user: {synthbotUserId}", synthbotUserId);
            // Update the token in the DB for future auth
            await UpdateDbAsync(userToken);

            return(userToken);
        }