using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Utils.Jwt;
using Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;

namespace PMS.NetCore.Filter
{
    /// <summary>
    /// 业主登录授权验证
    /// </summary>
    public class TokenAuthorizeByOwner : Attribute, IAuthorizationFilter
    {
        private ITokenHelper tokenHelper;
        private readonly IOptions<JWTConfig> _options;
        private NLog.Logger logger;
        /// <summary>
        /// 过滤器实现通用token验证
        /// </summary>
        /// <param name="_tokenHelper"></param>
        /// <param name="options"></param>
        public TokenAuthorizeByOwner(ITokenHelper _tokenHelper, IOptions<JWTConfig> options) //通过依赖注入得到数据访问层实例
        {
            tokenHelper = _tokenHelper;
            _options = options;
            logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
            logger.Debug("TokenAuthorizeByOwner 实例创建");
        }
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            logger.Debug("TokenAuthorizeByOwner OnAuthorization 开始");
            ApiResponse ret = new ApiResponse();
            if (HasAllowAnonymous(context))
            {
                ret.IsSuccess = true;
                ret.Code = 200;
                ret.ErrMsg = "";
                return;
            }
            try
            {
                //获取token
                //object tokenobj = context.ActionArguments["token"];//前端地址栏参数传参
                var token = context.HttpContext.Request.Headers["Authorization"].ToString();//前端写在header里面获取的
                logger.Info($"Authorization token:{token}");
                if (token.IsNullOrEmpty())
                {
                    ret.IsSuccess = false;
                    ret.Code = 201;
                    ret.ErrMsg = "token不能为空";
                    context.Result = new JsonResult(ret);
                    return;
                }


                string userId = "";
                //验证jwt,同时取出来jwt里边的用户ID
                TokenType tokenType = tokenHelper.ValiTokenState(token, a => a["iss"] == _options.Value.Issuer && a["aud"] == _options.Value.Audience, action => { userId = action["UserID"]; });
                if (tokenType == TokenType.Fail)
                {
                    ret.IsSuccess = false;
                    ret.Code = 202;
                    ret.ErrMsg = "token验证失败";
                    context.Result = new JsonResult(ret);
                    return;
                }
                if (tokenType == TokenType.Expired)
                {
                    ret.IsSuccess = false;
                    ret.Code = 205;
                    ret.ErrMsg = "token已经过期";
                    context.Result = new JsonResult(ret);
                }
                if (!string.IsNullOrEmpty(userId))
                {
                    //给控制器传递参数(需要什么参数其实可以做成可以配置的，在过滤器里边加字段即可)
                    //context.ActionArguments.Add("userId", Convert.ToInt32(userId));


                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                throw;
            }
        }


        /// <summary>
        /// 用于判断Action有没有AllowAnonymous标签
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private bool HasAllowAnonymous(AuthorizationFilterContext context)
        {
            logger.Debug("TokenAuthorizeByOwner HasAllowAnonymous 开始");
            var filters = context.Filters;
            for (var i = 0; i < filters.Count; i++)
            {
                if (filters[i] is IAllowAnonymousFilter)
                {
                    return true;
                }
            }

            var endpoint = context.HttpContext.GetEndpoint();
            if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
            {
                return true;
            }

            return false;
        }
    }
}
