using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.JSInterop;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text.Json;
using phronCare.UIBlazor.Extensions;

namespace phronCare.UIBlazor.Services.Authorization
{
    public class CustomAuthorizationProvider : AuthenticationStateProvider, ILoginService
    {
        private readonly IJSExtensions js;
        private readonly HttpClient httpClient;
        public static readonly string TOKENKEY = "phronCareTokenKey";
        private AuthenticationState Anonimo => new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));

        public CustomAuthorizationProvider(IJSRuntime _js, HttpClient httpClient)
        {
            this.httpClient = httpClient;
            js = new IJSExtensions(_js);
        }

        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var token = await js.GetFromLocalStorage(TOKENKEY);

            if (string.IsNullOrWhiteSpace(token) || !IsJwtFormat(token))
            {
                await js.RemoveItem(TOKENKEY);
                return Anonimo;
            }

            return BuildAuthenticationState(token);
        }

        private AuthenticationState BuildAuthenticationState(string token)
        {
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt")));
        }

        public async Task<TokenData> GetTokenData()
        {
            var authState = await GetAuthenticationStateAsync();
            var user = authState.User;

            if (user.Identity is null || !user.Identity.IsAuthenticated)
                throw new InvalidOperationException("Usuario no autenticado.");

            var tokenString = await js.GetFromLocalStorage(TOKENKEY); // <-- ACA RECUPERAMOS EL JWT

            return new TokenData
            {
                userName = user.Identity.Name ?? string.Empty,
                role = user.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value ?? string.Empty,
                token = tokenString ?? string.Empty, // <-- ACA SETEAMOS el token string
                expiryTimeStamp = DateTime.UtcNow
            };
        }
        //public async Task<TokenData> GetTokenData()
        //{
        //    var authState = await GetAuthenticationStateAsync();
        //    var user = authState.User;

        //    if (user.Identity is null || !user.Identity.IsAuthenticated)
        //        throw new InvalidOperationException("Usuario no autenticado.");

        //    return new TokenData
        //    {
        //        userName = user.Identity.Name ?? string.Empty,
        //        role = user.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value ?? string.Empty,
        //        expiryTimeStamp = DateTime.UtcNow // Opcional: ajustar si extraes exp claim
        //    };
        //}

        //public async Task Login(string token)
        //{
        //    await js.RemoveItem(TOKENKEY);
        //    await js.SetInLocalStorage(TOKENKEY, token);
        //    var authState = BuildAuthenticationState(token);
        //    NotifyAuthenticationStateChanged(Task.FromResult(authState));
        //}
        public async Task Login(string tokenJson)
        {
            var tokenData = JsonSerializer.Deserialize<TokenData>(tokenJson);

            if (tokenData is null || string.IsNullOrWhiteSpace(tokenData.token))
                throw new Exception("Token inválido o mal formado.");

            await js.RemoveItem(TOKENKEY);
            await js.SetInLocalStorage(TOKENKEY, tokenData.token); // ✔️ Guardamos solo el JWT string

            var authState = BuildAuthenticationState(tokenData.token);
            NotifyAuthenticationStateChanged(Task.FromResult(authState));
        }
        public async Task Logout()
        {
            httpClient.DefaultRequestHeaders.Authorization = null;
            await js.RemoveItem(TOKENKEY);
            NotifyAuthenticationStateChanged(Task.FromResult(Anonimo));
        }

        private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
        {
            var claims = new List<Claim>();
            var payload = jwt.Split('.')[1];
            var jsonBytes = ParseBase64WithoutPadding(payload);
            var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes);

            if (keyValuePairs != null && keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles))
            {
                var rolesString = roles?.ToString() ?? string.Empty;

                if (!string.IsNullOrEmpty(rolesString))
                {
                    if (rolesString.Trim().StartsWith("["))
                    {
                        var parsedRoles = JsonSerializer.Deserialize<string[]>(rolesString) ?? Array.Empty<string>();
                        foreach (var parsedRole in parsedRoles)
                        {
                            claims.Add(new Claim(ClaimTypes.Role, parsedRole));
                        }
                    }
                    else
                    {
                        claims.Add(new Claim(ClaimTypes.Role, rolesString));
                    }
                }

                keyValuePairs.Remove(ClaimTypes.Role);
            }

            if (keyValuePairs != null)
            {
                claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value?.ToString() ?? "defaultValue")));
            }

            return claims;
        }

        private byte[] ParseBase64WithoutPadding(string base64)
        {
            switch (base64.Length % 4)
            {
                case 2: base64 += "=="; break;
                case 3: base64 += "="; break;
            }
            return Convert.FromBase64String(base64);
        }

        private bool IsJwtFormat(string token)
        {
            return token?.Count(c => c == '.') == 2;
        }

        public class TokenData
        {
            public string userName { get; set; } = string.Empty;
            public string role { get; set; } = string.Empty;
            public string token { get; set; } = string.Empty;
            public DateTime expiryTimeStamp { get; set; }
        }
    }
}
