using DiunaBI.UI.Shared.Services;
using Microsoft.Maui.Authentication;
using System.Text.Json;

namespace DiunaBI.UI.Mobile.Services;

/// <summary>
/// Mobile implementation of Google authentication using WebAuthenticator
/// Opens OAuth in native browser
/// </summary>
public class MobileGoogleAuthService : IGoogleAuthService
{
    private readonly AuthService _authService;
    private const string GoogleClientId = "784258364493-t8g2bq0utgm9ac3pr8umov6i76uls65s.apps.googleusercontent.com";
    private const string RedirectUri = "com.diunabi:/oauth2redirect";

    public MobileGoogleAuthService(AuthService authService)
    {
        _authService = authService;
    }

    public async Task<bool> SignInAsync()
    {
        try
        {
            Console.WriteLine("🔐 Starting mobile Google authentication...");

            // Build Google OAuth URL - use code flow with iOS URL scheme
            var state = Guid.NewGuid().ToString("N");
            var codeVerifier = GenerateCodeVerifier();
            var codeChallenge = GenerateCodeChallenge(codeVerifier);

            var authUrl = "https://accounts.google.com/o/oauth2/v2/auth" +
                         $"?client_id={GoogleClientId}" +
                         $"&redirect_uri={Uri.EscapeDataString(RedirectUri)}" +
                         $"&response_type=code" +
                         $"&scope={Uri.EscapeDataString("openid profile email")}" +
                         $"&state={state}" +
                         $"&code_challenge={codeChallenge}" +
                         $"&code_challenge_method=S256";

            Console.WriteLine($"📱 Opening browser for Google OAuth...");

            var result = await WebAuthenticator.Default.AuthenticateAsync(
                new Uri(authUrl),
                new Uri(RedirectUri));

            Console.WriteLine($"✅ Got response from Google OAuth");

            // Extract authorization code
            if (result.Properties.TryGetValue("code", out var code))
            {
                Console.WriteLine($"✅ Got authorization code");

                // Exchange code for ID token
                var idToken = await ExchangeCodeForToken(code, codeVerifier);

                if (string.IsNullOrEmpty(idToken))
                {
                    Console.WriteLine("❌ Failed to exchange code for token");
                    return false;
                }

                Console.WriteLine($"✅ Got ID token, length: {idToken.Length}");

                // Decode the JWT to get user info
                var userInfo = DecodeJwtPayload(idToken);
                var root = userInfo.RootElement;

                var fullName = root.GetProperty("name").GetString() ?? "";
                var email = root.GetProperty("email").GetString() ?? "";
                var avatarUrl = root.TryGetProperty("picture", out var pic) ? pic.GetString() ?? "" : "";

                Console.WriteLine($"👤 User: {fullName} ({email})");

                // Validate with backend
                (bool success, string? errorMessage) = await _authService.ValidateWithBackendAsync(
                    idToken, fullName, email, avatarUrl);

                if (success)
                {
                    Console.WriteLine("✅ Backend validation successful");
                    return true;
                }
                else
                {
                    Console.WriteLine($"❌ Backend validation failed: {errorMessage}");
                    return false;
                }
            }

            Console.WriteLine("❌ No authorization code in OAuth response");
            return false;
        }
        catch (TaskCanceledException)
        {
            Console.WriteLine("ℹ️ User cancelled authentication");
            return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"❌ Mobile authentication error: {ex.Message}");
            Console.WriteLine($"Stack: {ex.StackTrace}");
            return false;
        }
    }

    private async Task<string?> ExchangeCodeForToken(string code, string codeVerifier)
    {
        try
        {
            using var httpClient = new HttpClient();

            var tokenRequest = new Dictionary<string, string>
            {
                { "code", code },
                { "client_id", GoogleClientId },
                { "redirect_uri", RedirectUri },
                { "grant_type", "authorization_code" },
                { "code_verifier", codeVerifier }
            };

            var response = await httpClient.PostAsync(
                "https://oauth2.googleapis.com/token",
                new FormUrlEncodedContent(tokenRequest));

            if (!response.IsSuccessStatusCode)
            {
                var error = await response.Content.ReadAsStringAsync();
                Console.WriteLine($"❌ Token exchange failed: {error}");
                return null;
            }

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

            return doc.RootElement.GetProperty("id_token").GetString();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"❌ Error exchanging code: {ex.Message}");
            return null;
        }
    }

    private string GenerateCodeVerifier()
    {
        var bytes = new byte[32];
        System.Security.Cryptography.RandomNumberGenerator.Fill(bytes);
        return Convert.ToBase64String(bytes)
            .TrimEnd('=')
            .Replace('+', '-')
            .Replace('/', '_');
    }

    private string GenerateCodeChallenge(string codeVerifier)
    {
        using var sha256 = System.Security.Cryptography.SHA256.Create();
        var bytes = System.Text.Encoding.ASCII.GetBytes(codeVerifier);
        var hash = sha256.ComputeHash(bytes);
        return Convert.ToBase64String(hash)
            .TrimEnd('=')
            .Replace('+', '-')
            .Replace('/', '_');
    }

    private JsonDocument DecodeJwtPayload(string token)
    {
        try
        {
            var parts = token.Split('.');
            if (parts.Length != 3)
                throw new Exception("Invalid JWT format");

            var payload = parts[1];
            // Add padding if needed
            var paddingNeeded = (4 - (payload.Length % 4)) % 4;
            payload += new string('=', paddingNeeded);

            // Convert from base64url to base64
            payload = payload.Replace('-', '+').Replace('_', '/');

            var jsonBytes = Convert.FromBase64String(payload);
            return JsonDocument.Parse(jsonBytes);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"❌ Error decoding JWT: {ex.Message}");
            throw;
        }
    }
}
