using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dodohold.core;


namespace molilian.core
{
    public class AdminProvider : IAuthorizationProvider
    {
        public string Domain => "admin";

        AccessTokenCore tokenCore = new AccessTokenCore();
        AdminPermissionCore permissionCore = new AdminPermissionCore();


        /// <summary>
        /// 验证是否未授权
        /// </summary>
        /// <param name="request">客户请求的token和scope（域）</param>
        /// <param name="logicAttr">受访问的权限属性</param>
        /// <returns></returns>
        public bool Verified(ActionExecutingContext context, (string ticket, string domain) request, MyAuthorizeAttribute logicAttr)
        {
            //tikect 为空，直接返回 false
            if (string.IsNullOrEmpty(request.ticket)) { return false; }

            //如果接口里面要求验证domain，就判断是否匹配当前domain
            if (!string.IsNullOrEmpty(logicAttr.Domain) && !logicAttr.Domain.Equals(request.domain)) { return false; }


            AccessTokenDTO accessTicket = (AccessTokenDTO)Get(request.domain, request.ticket);
            //从内存中获取ticket，没有就返回失败
            if (accessTicket == null) { return false; }

            //tikcet 设置永不过期，就直接返回 true
            if (accessTicket.ExpiresIn == 0) { return true; }
            DateTime expiresTime = (accessTicket.create_time + accessTicket.ExpiresIn).Convert2Datetime();

            //ticket 有效期还没到也返回true
            if (expiresTime > DateTime.Now) { return true; }

            //这里拿到 actionName 和 actionMethod ，但是实际上并没有去验证
            string actionName = null;
            if (context.ActionDescriptor is ControllerActionDescriptor actionDescriptor)
            {
                actionName = actionDescriptor.ActionName;
            }
            string actionMethod = context.HttpContext.Request.Method;


            //permission == null 就是没授权咯
            var permission = accessTicket.Permissions.Where(s => s.ResourceFlag.Equals(actionName) && s.ActionFlag.Equals(actionMethod)).FirstOrDefault();
            if (permission == null) { return false; }

            return false;
        }


        public IAccessTokenDTO Get(HttpContext context)
        {
            var (accessToken, domain) = context.GetAccessToken();
            return Get(domain, accessToken);
        }

        /// <summary>
        /// 获取token缓存(从内存缓存中)
        /// </summary>
        /// <param name="token">客户请求的token</param>
        /// <returns></returns>
        public IAccessTokenDTO Get(string domain, string accessTicket)
        {
            var accessToken = tokenCore.Get(domain, accessTicket);
            if (accessToken == null) { return null; }

            //todo 这里除了获取accesstoken以外 还得获取一下授权
            string roleIds = accessToken.AccessRoles;
            //if (!string.IsNullOrEmpty(roleIds))
            //{
            //    accessToken.Permissions = permissionCore.GetList(new { id = roleIds.ConvertToIntArray() })?.List;
            //}
            return accessToken;
        }

        /// <summary>
        /// 注销授权
        /// </summary>
        /// <param name="accessTicket"></param>
        /// <returns></returns>
        public int Revoke(string doamin, string accessTicket)
        {
            return tokenCore.Delete(doamin, accessTicket);
        }

        /// <summary>
        /// 创建一个授权
        /// </summary>
        /// <param name="key"></param>
        /// <param name="secret"></param>
        /// <param name="roles"></param>
        /// <param name="domain"></param>
        /// <param name="clientIp"></param>
        /// <returns></returns>
        public IAccessTokenDTO Create(long id, string key, string secret, string roles, string domain, string clientIp)
        {
            AccessTokenDTO token = Generate(id, key, secret, roles, domain, clientIp);
            tokenCore.Create(token);
            return token;
        }

        /// <summary>
        /// 工具类 ，产生一个 token
        /// </summary>
        /// <param name="accessKey"></param>
        /// <param name="secret"></param>
        /// <param name="accessRoles"></param>
        /// <param name="domain"></param>
        /// <param name="clientIp"></param>
        /// <returns></returns>
        public AccessTokenDTO Generate(long id, string accessKey, string secret, string roles, string domain, string clientIp)
        {
            DateTime now = DateTime.Now;
            AccessTokenDTO token = new AccessTokenDTO
            {
                AccessId = id,
                AccessKey = accessKey,
                AccessRoles = roles,
                create_time = now.Convert2UnixTimestamp(),
                ExpiresIn = 0,
                Domain = domain,
                ClientIp = clientIp,
                AccessTicket = $"{accessKey}|{secret}|{roles}|{domain}|{now}|{clientIp}".ToAES256()
            };
            return token;
        }
    }
}
