using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using QRRapidoApp.Models.ViewModels;
using QRRapidoApp.Services;
using System.Security.Claims;

namespace QRRapidoApp.Controllers
{
    public class AccountController : Controller
    {
        private readonly IUserService _userService;
        private readonly AdDisplayService _adDisplayService;
        private readonly ILogger<AccountController> _logger;
        private readonly IConfiguration _configuration;

        public AccountController(IUserService userService, AdDisplayService adDisplayService,
                                ILogger<AccountController> logger, IConfiguration configuration)
        {
            _userService = userService;
            _adDisplayService = adDisplayService;
            _logger = logger;
            _configuration = configuration;
        }

        [HttpGet]
        public IActionResult Login(string returnUrl = "/")
        {
            _adDisplayService.SetViewBagAds(ViewBag);
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        [HttpGet]
        public IActionResult LoginGoogle(string returnUrl = "/")
        {
            var baseUrl = _configuration.GetSection("App:BaseUrl").Value;
            var safeReturn = Url.IsLocalUrl(returnUrl) ? returnUrl : "/";
            var properties = new AuthenticationProperties
            {
                RedirectUri = $"{baseUrl}/Account/GoogleCallback?returnUrl={Uri.EscapeDataString(safeReturn)}"
            };
            return Challenge(properties, GoogleDefaults.AuthenticationScheme);
        }

        [HttpGet]
        public IActionResult LoginMicrosoft(string returnUrl = "/")
        {
            var baseUrl = _configuration.GetSection("App:BaseUrl").Value;
            var safeReturn = Url.IsLocalUrl(returnUrl) ? returnUrl : "/";
            var properties = new AuthenticationProperties
            {
                RedirectUri = $"{baseUrl}/Account/MicrosoftCallback?returnUrl={Uri.EscapeDataString(safeReturn)}"
            };
            return Challenge(properties, MicrosoftAccountDefaults.AuthenticationScheme);
        }

        [HttpGet]
        public async Task<IActionResult> GoogleCallback(string returnUrl = "/")
        {
            var destination = await HandleExternalLoginCallbackAsync(GoogleDefaults.AuthenticationScheme, returnUrl);
            return Redirect(destination ?? "/");
        }

        [HttpGet]
        public async Task<IActionResult> MicrosoftCallback(string returnUrl = "/")
        {
            var destination = await HandleExternalLoginCallbackAsync(MicrosoftAccountDefaults.AuthenticationScheme, returnUrl);
            return Redirect(destination ?? "/");
        }

        private async Task<string> HandleExternalLoginCallbackAsync(string scheme, string returnUrl = "/")
        {
            try
            {
                _adDisplayService.SetViewBagAds(ViewBag);

                // Validate returnUrl to prevent open redirect
                if (!Url.IsLocalUrl(returnUrl))
                    returnUrl = "/";

                // Prevent redirect loop
                if (returnUrl.Contains("/Account/Login", StringComparison.OrdinalIgnoreCase))
                    returnUrl = "/";

                // OAuth middleware already signed in via cookie at /signin-google or /signin-microsoft
                // with the provider's claims. Authenticate from that cookie to get the provider identity.
                var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
                if (!result.Succeeded)
                {
                    _logger.LogWarning("Cookie authentication failed after {Scheme} OAuth callback", scheme);
                    return "/Account/Login";
                }

                var email = result.Principal?.FindFirst(ClaimTypes.Email)?.Value;
                var name = result.Principal?.FindFirst(ClaimTypes.Name)?.Value;
                var providerId = result.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value;

                if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(providerId))
                {
                    _logger.LogWarning($"Missing required claims from {scheme} authentication");
                    return "/Account/Login";
                }

                // Find or create user
                var user = await _userService.GetUserByProviderAsync(scheme, providerId);
                bool isNewUser = user == null;
                if (isNewUser)
                {
                    // Fix CS8625: Ensure name is not null
                    var safeName = !string.IsNullOrEmpty(name) ? name : (email ?? "User");
                    user = await _userService.CreateUserAsync(email, safeName, scheme, providerId);
                    // Auto-create first API key so user can start immediately
                    try
                    {
                        var (rawKey, _) = await _userService.GenerateApiKeyAsync(user.Id, "Minha primeira key");
                        TempData["NewKey"] = rawKey;
                        TempData["NewKeyName"] = "Minha primeira key";
                        _logger.LogInformation("Auto-created API key for new user {UserId}", user.Id);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to auto-create API key for new user {UserId}", user.Id);
                    }
                }
                else
                {
                    await _userService.UpdateLastLoginAsync(user.Id);
                }

                // Create application claims
                var claims = new List<Claim>
                {
                    new Claim(ClaimTypes.NameIdentifier, user.Id ?? string.Empty), // Fix CS8625
                    new Claim(ClaimTypes.Email, user.Email ?? string.Empty), // Fix CS8625
                    new Claim(ClaimTypes.Name, user.Name ?? string.Empty), // Fix CS8625
                    new Claim("Provider", user.Provider ?? string.Empty),
                    new Claim("IsPremium", user.IsPremium.ToString())
                };

                var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
                var authProperties = new AuthenticationProperties
                {
                    IsPersistent = true,
                    ExpiresUtc = DateTimeOffset.UtcNow.AddDays(30)
                };

                await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
                    new ClaimsPrincipal(claimsIdentity), authProperties);

                return returnUrl;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error in external login callback for {scheme}");
                return "/Account/Login";
            }
        }

        [HttpPost]
        [Authorize]
        public async Task<IActionResult> Logout()
        {
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return RedirectToAction("Index", "Home");
        }

        [HttpGet]
        [Authorize]
        public async Task<IActionResult> Profile()
        {
            var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (string.IsNullOrEmpty(userId))
            {
                return RedirectToAction("Login");
            }

            var user = await _userService.GetUserAsync(userId);
            if (user == null)
            {
                return RedirectToAction("Login");
            }

            // Ensure we are passing a non-null userId
            ViewBag.QRHistory = await _userService.GetUserQRHistoryAsync(userId, 10);
            ViewBag.MonthlyQRCount = await _userService.GetQRCountThisMonthAsync(userId);
            ViewBag.IsPremium = await _adDisplayService.HasValidPremiumSubscription(userId);
            _adDisplayService.SetViewBagAds(ViewBag);

            return View(user);
        }

        [HttpGet]
        public async Task<IActionResult> AdFreeStatus()
        {
            var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;

            if (string.IsNullOrEmpty(userId))
            {
                return Json(new AdFreeStatusViewModel
                {
                    IsAdFree = false,
                    TimeRemaining = 0,
                    IsPremium = false
                });
            }

            var shouldShowAds = await _adDisplayService.ShouldShowAds(userId);
            var isPremium = await _adDisplayService.HasValidPremiumSubscription(userId);
            var expiryDate = await _adDisplayService.GetAdFreeExpiryDate(userId);
            var status = await _adDisplayService.GetAdFreeStatusAsync(userId);

            return Json(new AdFreeStatusViewModel
            {
                IsAdFree = !shouldShowAds,
                TimeRemaining = isPremium ? int.MaxValue : 0,
                IsPremium = isPremium,
                ExpiryDate = expiryDate,
                SessionType = status
            });
        }

        [HttpPost]
        [Authorize]
        public async Task<IActionResult> ExtendAdFreeTime(int minutes)
        {
            var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;

            // Método removido - sem extensão de tempo ad-free
            return Json(new { success = false, message = "Feature not available" });
        }

        [HttpGet]
        [Authorize]
        public async Task<IActionResult> History()
        {
            _adDisplayService.SetViewBagAds(ViewBag);
            var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (string.IsNullOrEmpty(userId))
            {
                return RedirectToAction("Login");
            }

            var history = await _userService.GetUserQRHistoryAsync(userId, 50);
            return View(history);
        }

        [HttpPost]
        [Authorize]
        public async Task<IActionResult> UpdatePreferences(string language)
        {
            var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (string.IsNullOrEmpty(userId))
            {
                return Json(new { success = false });
            }

            try
            {
                var user = await _userService.GetUserAsync(userId);
                if (user != null)
                {
                    user.PreferredLanguage = language;
                    await _userService.UpdateUserAsync(user);
                    return Json(new { success = true });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error updating preferences for user {userId}");
            }

            return Json(new { success = false });
        }
    }

}