using System.Text.Json;
using Microsoft.Extensions.Logging;

namespace ScadaLink.NotificationService;

/// <summary>
/// WP-11: OAuth2 Client Credentials token lifecycle — fetch, cache, refresh on expiry.
/// Used for Microsoft 365 SMTP authentication.
/// </summary>
public class OAuth2TokenService
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ILogger<OAuth2TokenService> _logger;
    private string? _cachedToken;
    private DateTimeOffset _tokenExpiry = DateTimeOffset.MinValue;
    private readonly SemaphoreSlim _lock = new(1, 1);

    public OAuth2TokenService(
        IHttpClientFactory httpClientFactory,
        ILogger<OAuth2TokenService> logger)
    {
        _httpClientFactory = httpClientFactory;
        _logger = logger;
    }

    /// <summary>
    /// Gets a valid access token, refreshing if expired.
    /// Credentials format: "tenantId:clientId:clientSecret"
    /// </summary>
    public async Task<string> GetTokenAsync(string credentials, CancellationToken cancellationToken = default)
    {
        if (_cachedToken != null && DateTimeOffset.UtcNow < _tokenExpiry)
        {
            return _cachedToken;
        }

        await _lock.WaitAsync(cancellationToken);
        try
        {
            // Double-check after acquiring lock
            if (_cachedToken != null && DateTimeOffset.UtcNow < _tokenExpiry)
            {
                return _cachedToken;
            }

            var parts = credentials.Split(':', 3);
            if (parts.Length < 3)
            {
                throw new InvalidOperationException("OAuth2 credentials must be 'tenantId:clientId:clientSecret'");
            }

            var tenantId = parts[0];
            var clientId = parts[1];
            var clientSecret = parts[2];

            var client = _httpClientFactory.CreateClient("OAuth2");
            var tokenUrl = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";

            var form = new FormUrlEncodedContent(new Dictionary<string, string>
            {
                ["grant_type"] = "client_credentials",
                ["client_id"] = clientId,
                ["client_secret"] = clientSecret,
                ["scope"] = "https://outlook.office365.com/.default"
            });

            var response = await client.PostAsync(tokenUrl, form, cancellationToken);
            response.EnsureSuccessStatusCode();

            var json = await response.Content.ReadAsStringAsync(cancellationToken);
            using var doc = JsonDocument.Parse(json);

            _cachedToken = doc.RootElement.GetProperty("access_token").GetString()
                ?? throw new InvalidOperationException("No access_token in OAuth2 response");

            var expiresIn = doc.RootElement.GetProperty("expires_in").GetInt32();
            _tokenExpiry = DateTimeOffset.UtcNow.AddSeconds(expiresIn - 60); // Refresh 60s before expiry

            _logger.LogInformation("OAuth2 token refreshed, expires in {ExpiresIn}s", expiresIn);
            return _cachedToken;
        }
        finally
        {
            _lock.Release();
        }
    }
}
