using LiteCharms.Features.Api.Configuration; using LiteCharms.Features.Api.Models; using LiteCharms.Features.Api.Sdk; namespace LiteCharms.Features.Api; public sealed class TokenService(IConnectApi connectApi, IOptions clientOptions) { private readonly LiteCharmsClientSettings clientSettings = clientOptions.Value; public async Task> GenerateAsync(CancellationToken cancellationToken = default) { try { var request = new TokenRequest { ClientId = clientSettings.ClientId, ClientSecret = clientSettings.ClientSecret, GrantType = clientSettings.GrantType, Scope = clientSettings.Scope, }; using var response = await connectApi.GetToken(request, cancellationToken); var contentRaw = await response.Content.ReadAsStringAsync(cancellationToken); if (string.IsNullOrWhiteSpace(contentRaw)) return Result.Fail(new Error($"The authentication endpoint returned an empty payload. Status code: {response.StatusCode}")); if (response.IsSuccessStatusCode) { var tokenResponse = JsonSerializer.Deserialize(contentRaw); return !string.IsNullOrWhiteSpace(tokenResponse?.AccessToken) ? Result.Ok(tokenResponse) : Result.Fail(new Error("Authentication succeeded, but no access token was found in the response payload.")); } try { var errorResult = JsonSerializer.Deserialize(contentRaw); if (errorResult != null) { string summary = $"{errorResult.Error}: {errorResult.ErrorDescription}"; return Result.Fail(new Error(summary)); } } catch { return Result.Fail(new Error($"Authentication failed: {contentRaw}")); } return Result.Fail(new Error($"Authentication failed with status code: {response.StatusCode}")); } catch (OperationCanceledException ex) { return Result.Fail(new Error("The token generation request was canceled.").CausedBy(ex)); } catch (Exception ex) { return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } }