using Blazored.LocalStorage;
using CMSMicroservice.Protobuf.Protos.User;
using Microsoft.AspNetCore.Components;
using MudBlazor;
using System.IdentityModel.Tokens.Jwt;

namespace FrontOffice.Main.Utilities;

public class AuthService
{
    private readonly ILocalStorageService _localStorage;
    private readonly NavigationManager _navigation;
    private readonly ISnackbar _snackbar;
    private readonly UserAuthInfo _userAuthInfo;
    private readonly CMSMicroservice.Protobuf.Protos.User.UserContract.UserContractClient _userContract;
    private readonly ILogger<AuthService> _logger;

    private const string TokenStorageKey = "auth:token";

    public AuthService(
        ILocalStorageService localStorage, 
        NavigationManager navigation, 
        ISnackbar snackbar, 
        UserAuthInfo userAuthInfo,
        CMSMicroservice.Protobuf.Protos.User.UserContract.UserContractClient userContract,
        ILogger<AuthService> logger)
    {
        _localStorage = localStorage;
        _navigation = navigation;
        _snackbar = snackbar;
        _userAuthInfo = userAuthInfo;
        _userContract = userContract;
        _logger = logger;
    }

    public async Task<bool> IsAuthenticatedAsync()
    {
        var token = await _localStorage.GetItemAsync<string>(TokenStorageKey);
        return !string.IsNullOrWhiteSpace(token);
    }

    public async Task<string?> GetTokenAsync()
    {
        return await _localStorage.GetItemAsync<string>(TokenStorageKey);
    }
    public async Task<bool> IsCompleteRegisterAsync()
    {
       await InitUserAuthInfo();
       if (!string.IsNullOrWhiteSpace(_userAuthInfo.NationalCode) && !string.IsNullOrWhiteSpace(_userAuthInfo.FirstName) && !string.IsNullOrWhiteSpace(_userAuthInfo.LastName) && _userAuthInfo.IsSignMainContract)
        {
            return true;
        }
        return false;
    }
    public bool IsCompleteRegister()
    {
         InitUserAuthInfo().GetAwaiter().GetResult();
         if (!string.IsNullOrWhiteSpace(_userAuthInfo.NationalCode) && !string.IsNullOrWhiteSpace(_userAuthInfo.FirstName) && !string.IsNullOrWhiteSpace(_userAuthInfo.LastName) && _userAuthInfo.IsSignMainContract)
         {
             return true;
         }
         return false;
    }
    public async Task<UserAuthInfo> GetUserAuthInfo()
    {
       await InitUserAuthInfo();
        return _userAuthInfo;
    }
 
    public async Task InitUserAuthInfo()
    {
        var claims = await GetTokenClaimsAsync();
        _userAuthInfo.UserClaims= claims;
        var userIdStr = claims.FirstOrDefault(c => c.key == "UserId" || c.key == "sub" || c.key == "nameid").value;
        var firstName = claims.FirstOrDefault(c => c.key == "FirstName").value;
        var lastName = claims.FirstOrDefault(c => c.key == "LastName").value;
        var nationalCode = claims.FirstOrDefault(c => c.key == "NationalCode").value;
        var mobileNumber = claims.FirstOrDefault(c => c.key == "MobileNumber").value;
        var isSignMainContractStr = claims.FirstOrDefault(c => c.key == "IsSignMainContract").value;
        var hasPurchasedPackageStr = claims.FirstOrDefault(c => c.key == "HasPurchasedPackage").value;
        var isClubMemberActiveStr = claims.FirstOrDefault(c => c.key == "IsClubMemberActive").value;
        var hasAddressStr = claims.FirstOrDefault(c => c.key == "HasAddress").value;
        
        _userAuthInfo.UserId = long.TryParse(userIdStr, out var userId) ? userId : 0;
        _userAuthInfo.FirstName = firstName ?? string.Empty;
        _userAuthInfo.LastName = lastName ?? string.Empty;
        _userAuthInfo.NationalCode = nationalCode ?? string.Empty;
        _userAuthInfo.MobileNumber = mobileNumber ?? string.Empty;
        _userAuthInfo.IsSignMainContract = bool.TryParse(isSignMainContractStr, out var isSignMainContract) && isSignMainContract;
        _userAuthInfo.HasPurchasedPackage = bool.TryParse(hasPurchasedPackageStr, out var hasPurchased) && hasPurchased;
        _userAuthInfo.IsClubMemberActive = bool.TryParse(isClubMemberActiveStr, out var isClubActive) && isClubActive;
        _userAuthInfo.HasAddress = bool.TryParse(hasAddressStr, out var hasAddress) && hasAddress;
    }

    private async Task<List<(string key, string value)>?> GetTokenClaimsAsync()
    {
        var token = await GetTokenAsync();
        if (string.IsNullOrEmpty(token)) return null;
        var handler = new JwtSecurityTokenHandler();
        var jwtToken = handler.ReadJwtToken(token);
        return jwtToken.Claims.Select(c => (c.Type, c.Value)).ToList();
    }

    public async Task LogoutAsync()
    {
        await _localStorage.RemoveItemAsync(TokenStorageKey);
        await _localStorage.RemoveItemAsync("auth:phone-number");
        await _localStorage.RemoveItemAsync("auth:redirect");
        await _localStorage.RemoveItemAsync("referral:code");

        _snackbar.Add("با موفقیت از حساب کاربری خارج شدید.", Severity.Success);
        _navigation.NavigateTo(RouteConstants.Main.MainPage);
    }

    /// <summary>
    /// Refresh the user's token by calling the BFF RefreshToken API.
    /// If successful, the new token is stored and user info is updated.
    /// </summary>
    /// <returns>True if token was refreshed successfully</returns>
    public async Task<bool> RefreshTokenAsync()
    {
        try
        {
            var currentToken = await GetTokenAsync();
            if (string.IsNullOrEmpty(currentToken))
            {
                _logger.LogWarning("No token found for refresh");
                return false;
            }

            var response = await _userContract.RefreshTokenAsync(new RefreshTokenRequest
            {
                CurrentToken = currentToken
            });

            if (response.Success && !string.IsNullOrEmpty(response.Token))
            {
                // Store the new token
                await _localStorage.SetItemAsync(TokenStorageKey, response.Token);
                
                // Update user auth info with new token claims
                await InitUserAuthInfo();
                
                _logger.LogInformation("Token refreshed successfully");
                return true;
            }
            else
            {
                _logger.LogInformation("Token refresh not needed: {Message}", response.Message);
                return false;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to refresh token");
            return false;
        }
    }

    public async Task RequireAuthenticationAsync()
    {
        var isAuthenticated = await IsAuthenticatedAsync();
        if (!isAuthenticated)
        {
            _snackbar.Add("لطفاً ابتدا وارد حساب کاربری شوید.", Severity.Warning);
            _navigation.NavigateTo(RouteConstants.Main.MainPage);
        }
    }
}