using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Yi.Framework.Core.Authentication;

namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Authentication;

/// <summary>
/// 可刷新的鉴权提供者
/// </summary>
public class RefreshAuthenticationHandlerProvider : IRefreshAuthenticationHandlerProvider
{
    private Dictionary<string, IAuthenticationHandler> _handlerMap =
        new Dictionary<string, IAuthenticationHandler>((IEqualityComparer<string>)StringComparer.Ordinal);

    /// <summary>Constructor.</summary>
    /// <param name="schemes">The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider" />.</param>
    public RefreshAuthenticationHandlerProvider(IAuthenticationSchemeProvider schemes)
    {
        this.Schemes = schemes;
    }

    /// <summary>
    /// The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider" />.
    /// </summary>
    public IAuthenticationSchemeProvider Schemes { get; }

    /// <summary>Returns the handler instance that will be used.</summary>
    /// <param name="context">The context.</param>
    /// <param name="authenticationScheme">The name of the authentication scheme being handled.</param>
    /// <returns>The handler instance.</returns>
    public async Task<IAuthenticationHandler?> GetHandlerAsync(
        HttpContext context,
        string authenticationScheme)
    {
        IAuthenticationHandler handlerAsync;
        if (this._handlerMap.TryGetValue(authenticationScheme, out handlerAsync))
            return handlerAsync;
        AuthenticationScheme schemeAsync = await this.Schemes.GetSchemeAsync(authenticationScheme);
        if (schemeAsync == null)
            return (IAuthenticationHandler)null;

        if ((context.RequestServices.GetService(schemeAsync.HandlerType) ??
             ActivatorUtilities.CreateInstance(context.RequestServices, schemeAsync.HandlerType)) is
            IAuthenticationHandler handler)
        {
            handlerAsync = handler;
            await handler.InitializeAsync(schemeAsync, context);
            this._handlerMap[authenticationScheme] = handler;
        }

        return handlerAsync;
    }


    /// <summary>
    /// 刷新鉴权
    /// </summary>
    public void RefreshAuthentication()
    {
        _handlerMap = new Dictionary<string, IAuthenticationHandler>((IEqualityComparer<string>)StringComparer.Ordinal);
    }
}