using EasyCaching.Core;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace IRaCIS.Core.Application.Filter
{
    /// <summary>
    /// 主要为了 处理项目结束 锁库，不允许操作
    /// </summary>
    public class TrialResourceFilter : Attribute, IAsyncResourceFilter /* , IResourceFilter*/
    {
        private readonly IEasyCachingProvider _provider;
        private readonly IUserInfo _userInfo;


        public TrialResourceFilter(IEasyCachingProvider provider, IUserInfo userInfo)
        {
            _provider = provider;
            _userInfo = userInfo;
        }



        //优先选择异步的方法
        public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
        {
            #region 处理新的用户类型，不能操作项目相关接口

            // 后期列举出具体的类型，其他任何用户类型，都不允许操作
            if( _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA)
            {
                context.Result = new JsonResult(ResponseOutput.NotOk("对不起，你的账户没有操作权限。"));

                return ;
            }

            #endregion



            //TrialId 传递的途径多种，可能在path 可能在body  可能在数组中，也可能在对象中，可能就在url
            var trialIdStr = string.Empty;

            //先尝试从path中取TrialId 
            if (context.RouteData.Values.Keys.Any(t => t.Contains("trialId")))
            {
                var index = context.RouteData.Values.Keys.ToList().IndexOf("trialId");
                trialIdStr = context.RouteData.Values.Values.ToList()[index] as string;
            }
            else
            {
                #region body 中取数据

                //设置可以多次读
                context.HttpContext.Request.EnableBuffering();
                var reader = new StreamReader(context.HttpContext.Request.Body);
                var contentFromBody = await reader.ReadToEndAsync();
                //读取后，流的位置还原
                context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
                //context.HttpContext.Request.Body.Position = 0;

                //找到参数位置在字符串中的索引
                var trialIdIndex = contentFromBody.IndexOf("\"TrialId\"", StringComparison.OrdinalIgnoreCase);

                if (trialIdIndex > -1)
                {
                    trialIdStr = contentFromBody.Substring(trialIdIndex + "TrialId".Length + 4, 36);
                }
              
                #endregion
            }

            //通过path 或者body 找到trialId 了  
            if (trialIdStr != string.Empty)
            {

                //如果没缓存数据，可能定时任务没执行或者缓存丢失  在此重新缓存
                if (_provider.GetCount() == 0)
                {

                    var _trialRepository = context.HttpContext.RequestServices.GetService(typeof(IRepository<Trial>)) as IRepository<Trial>;

                    var list = _trialRepository.IfNullThrowException().Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
                      .ToList();

                    list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
                }

                var cacheResultDic = _provider.GetAll<string>(new[] { trialIdStr });

                var trialStatusStr = cacheResultDic[trialIdStr];


               //  这里是统一拦截 项目有关的操作允许情况(特殊的地方，比如项目配置（有的在多种状态（初始化，ongoing）都可以操作，有的仅仅在Initializing）还有  项目添加和更新，不走这里，特殊处理,不然在这里显得很乱，判断是哪个接口)
                if (trialStatusStr.Value == StaticData.TrialOngoing)
                {

                    await next.Invoke();

                }
                //  项目停止、或者完成  不允许操作

                else
                {
                    context.Result = new JsonResult(ResponseOutput.NotOk("只有项目状态处于进行中时,才允许进行操作"));

                }

            } 
          
            else
            {
                //如果项目相关接口没有传递trialId 会来到这里,提醒，以便修改

                context.Result = new JsonResult(ResponseOutput.NotOk("该接口参数中，没有传递项目编号，请核对。"));
            }


        }
    }
}