using System.Text.Json;
using Application.Abstractions.Authentication;
using Microsoft.Extensions.Logging;

namespace Infrastructure.Authentication;

internal sealed class GoogleTokenValidator(
    HttpClient httpClient,
    ILogger<GoogleTokenValidator> logger
) : IGoogleTokenValidator
{
    public async Task<GoogleUserInfo?> ValidateAsync(string credential, string clientId, CancellationToken ct)
    {
        try
        {
            var response = await httpClient.GetAsync(
                $"https://oauth2.googleapis.com/tokeninfo?id_token={credential}", ct
            );

            if (!response.IsSuccessStatusCode)
            {
                logger.LogWarning("Google token validation failed: {StatusCode}", response.StatusCode);
                return null;
            }

            var json = await response.Content.ReadAsStringAsync(ct);
            var payload = JsonSerializer.Deserialize<JsonElement>(json);

            // aud (audience) 검증
            var aud = payload.GetProperty("aud").GetString();
            if (aud != clientId)
            {
                logger.LogWarning("Google token aud mismatch: expected {Expected}, got {Actual}", clientId, aud);
                return null;
            }

            // 이메일 인증 여부 확인
            var emailVerified = payload.GetProperty("email_verified").GetString();
            if (emailVerified != "true")
            {
                logger.LogWarning("Google token email not verified");
                return null;
            }

            var email = payload.GetProperty("email").GetString()!;
            var sub = payload.GetProperty("sub").GetString()!;
            var name = payload.TryGetProperty("name", out var nameProp) ? nameProp.GetString() : null;
            var picture = payload.TryGetProperty("picture", out var picProp) ? picProp.GetString() : null;

            return new GoogleUserInfo(sub, email, name, picture);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Google token validation error");
            return null;
        }
    }
}