using System.Security.Claims;
using FoodsharingSiegen.Contracts;
using FoodsharingSiegen.Contracts.Entity;
using FoodsharingSiegen.Server.Data;
using FoodsharingSiegen.Server.Service;
using FoodsharingSiegen.Shared.Helper;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.EntityFrameworkCore;

namespace FoodsharingSiegen.Server.Auth
{
        /// <summary>
        /// The token auth state provider class (a. beging, 02.04.2022)
        /// </summary>
        /// <seealso cref="AuthenticationStateProvider"/>
        public class TokenAuthStateProvider : AuthenticationStateProvider
    {
        private FsContext Context { get; }

        #region Private Fields

        /// <summary> LocalStorageService </summary>
        private readonly LocalStorageService _localStorageService;
        
        #endregion

        #region Setup/Teardown

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="localStorageService"></param>
        /// <param name="context"></param>
        public TokenAuthStateProvider(LocalStorageService localStorageService, FsContext context)
        {
            Context = context;
            _localStorageService = localStorageService;
        }

        #endregion

        #region Override GetAuthenticationStateAsync

        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Get the current authenticationstate </summary>
        /// <remarks>   A. Beging, 02.02.2022. </remarks>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var token = await _localStorageService.GetItem<string>(StorageKeys.TokenKey);
            var tokenValid = AuthHelper.ValidateToken(token, out var user);

            var checkR = await CheckForceLogout(user);
            if (checkR.Success && checkR.Data)
                tokenValid = false;
            
            var identity = new ClaimsIdentity();
            if (tokenValid)
                identity = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Name, "user")
                }, "TODO");
            
            var claimsPrincipal = new ClaimsPrincipal(identity);
            return new AuthenticationState(claimsPrincipal);
        }

        #endregion

        #region Public Method MarkUserAsAuthenticated

        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Mark user as authenticated. </summary>
        /// <remarks>   A. Beging, 02.02.2022. </remarks>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        public void MarkUserAsAuthenticated() => NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());

        #endregion

        #region Public Method CheckForceLogout

        /// <summary>
        /// Checks the force logout using the specified user (a. beging, 11.04.2022)
        /// </summary>
        /// <param name="user">The user</param>
        /// <returns>A task containing an operation result of bool</returns>
        public async Task<OperationResult<bool>> CheckForceLogout(User? user)
        {
            try
            {
                if (user == null) return new OperationResult<bool>(new Exception());
                
                var anyR = await Context.Users!.AnyAsync(x => x.Id == user.Id && x.ForceLogout);
                return new OperationResult<bool>(anyR);
            }
            catch (Exception e)
            {
                return new OperationResult<bool>(e);
            }
        }

        #endregion
        
        #region Public Method MarkUserAsLoggedOut
        
        /// <summary>
        /// Marks the user as logged out (a. beging, 02.04.2022)
        /// </summary>
        public void MarkUserAsLoggedOut()
        {
            var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());
            var authState = Task.FromResult(new AuthenticationState(anonymousUser));
            NotifyAuthenticationStateChanged(authState);
        }

        #endregion
    }
}