using IRaCIS.Core.Application.BusinessFilter;
using IRaCIS.Core.Application.Helper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static IRaCIS.Core.Domain.Share.StaticData;

namespace IRaCIS.Core.Application.Filter;

public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _userInfo, IRepository<Trial> _trialRepository) : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        // 检查当前 endpoint 是否包含 TrialGlobalLimitAttribute 特性
        var trialLimitAttribute = context.HttpContext.GetEndpoint()?.Metadata.GetMetadata<TrialGlobalLimitAttribute>();

        if (trialLimitAttribute != null)
        {
            var optActions = trialLimitAttribute._optActions;


            // 这里开始执行原有的逻辑
            var requestHost = context.HttpContext.Request.Host;

            // 检查请求是否来自 localhost:6100
            if (requestHost.Host == "localhost" && (requestHost.Port == 6100 || requestHost.Port == 3305))
            {
                await next();
                return;
            }

            #region 特殊用户类型拦截
            // 用户类型检查  
            if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower() != "TrialDocument/userConfirm".ToLower())
            {
                //对不起，您的账户没有操作权限
                context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_NoAccessPermission")));

                return;
            }
            #endregion


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

            if (!string.IsNullOrWhiteSpace(context.HttpContext.Request.Query["trialId"]))
            {
                trialIdStr = context.HttpContext.Request.Query["trialId"];
            }

            //先尝试从path中取TrialId 
            else if (context.HttpContext.Request.RouteValues.Keys.Any(t => t.Contains("trialId")))
            {
                var index = context.HttpContext.Request.RouteValues.Keys.ToList().IndexOf("trialId");
                trialIdStr = context.HttpContext.Request.RouteValues.Values.ToList()[index] as string;
            }
            else if (context.HttpContext.Request.Headers["Referer"].ToString().Contains("trialId"))
            {
                var headerStr = context.HttpContext.Request.Headers["Referer"].ToString();

                var trialIdIndex = headerStr.IndexOf("trialId");


                var matchResult = Regex.Match(headerStr.Substring(trialIdIndex), @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");

                if (matchResult.Success)
                {
                    trialIdStr = matchResult.Value;
                }
                else
                {
                    //---正则取请求Refer 中trialId 失败，请联系开发人员核查
                    context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_ReferTrialIdFailed")));
                    return;
                }

            }
            else
            {
                #region body 中取数据

                //设置可以多次读
                context.HttpContext.Request.EnableBuffering();
                context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
                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)
                {
                    //  (?<="trialId" *: *").*?(?=",)

                    //使用正则 [0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}

                    var matchResult = Regex.Match(contentFromBody.Substring(trialIdIndex), @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");

                    if (matchResult.Success)
                    {
                        //有可能匹配错误   "trialId":"","documentId":"b8180000-3e2c-0016-9fe0-08da33f96236"  从缓存里面验证下

                        trialIdStr = matchResult.Value;

                        var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));

                        if (string.IsNullOrWhiteSpace(trialStatusStr))
                        {

                            //数据库 检查该项目Id不对
                            context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_ReferTrialIdFailed")));
                            return;

                        }
                    }
                    else
                    {
                        //---正则取请求Refer 中trialId 失败，请联系开发人员核查
                        context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_ReferTrialIdFailed")));
                        return;

                    }

                    //使用字符串取 如果是swagger  可能有时取的不对  因为空格的原因
                    //trialIdStr = contentFromBody.Substring(trialIdIndex + "TrialId".Length + 4, 3
                }

                #endregion
            }
            #endregion



            //通过path 或者body 找到trialId 了  
            if (!string.IsNullOrWhiteSpace(trialIdStr))
            {
                var trialStatusStr = await _fusionCache.GetOrSetAsync(CacheKeys.Trial(trialIdStr), _ => CacheHelper.GetTrialStatusAsync(Guid.Parse(trialIdStr), _trialRepository), TimeSpan.FromDays(7));

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

                    await next();

                }
                //  项目停止、或者完成  不允许操作
                else
                {
                    //---本次请求被配置规则拦截：项目状态处于进行中时,才允许操作,若此处逻辑有误，请联系开发人员修改
                    context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_InterceptedProjectStatusRule")));

                }

            }
            //添加项目  签名系统文档的时候  不做拦截   但是更新项目  签名项目文档的时候需要拦截
            else if (optActions.Any(t => t == TrialOpt.AddOrUpdateTrial || t == TrialOpt.SignSystemDocNoTrialId))
            {
                await next();
            }

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

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

        }
        else
        {
            // 如果没有 TrialGlobalLimitAttribute，则直接执行后续逻辑
            await next();
        }


    }
}
