using System;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Primitives;
using Siger.ApiCommon.Result;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Redis;

namespace Siger.ApiCommon.Filters
{
    public class ResultFilter: ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            context.HttpContext.Request.Headers.TryGetValue(ParameterConstant.Token, out StringValues value);

            if (!SkipResult(context))
            {
                var status = context.HttpContext.Response.StatusCode;
                if (status != (int) HttpStatusCode.OK)
                {
                    var error = context.Exception.InnerException != null ? context.Exception.InnerException.Message : context.Exception.Message;
                    context.Result = new ObjectResult(new ResultObject(0, (int)CommonEnum.SystemExcetion, error));

                    //RedisCache.Instance.AddFailedAPI(value, context.HttpContext.Request.Path, Convert.ToString((int)CommonEnum.SystemExcetion),
                    //    error, GetParameter(context));
                    return;
                }

                var origialResult = context.Result;
                switch (origialResult)
                {
                    case null:
                        //var error = context.Exception.InnerException != null ? context.Exception.InnerException.Message : context.Exception.Message;
                        //string msg;
                        //string paramter = GetParameter(context);
                        if (context.Exception is BadRequestException badRequestException)
                        {
                            var intmsg = (int)Convert.ChangeType(badRequestException.ExceptionEnum, typeof(int));
                            //msg = intmsg.ToStr();
                            //paramter = badRequestException.RequestParameter;
                            context.Result = new ObjectResult(new ResultObject(0, intmsg, null));
                        }
                        else if (context.Exception is ServerException serverException)
                        {
                            //msg = serverException.msg.ToStr();
                            context.Result = new ObjectResult(new ClientObject(0, serverException.msg, null));
                        }
                        else if (context.Exception is ClientException clintException)
                        {
                            //msg = clintException.msg;
                            context.Result = new ObjectResult(new ClientDeviceObject(0, clintException.msg, null));
                        }
                        else
                        {
                            //msg = Convert.ToString((int)CommonEnum.SystemExcetion);
                            context.Result = new ObjectResult(new ResultObject(0, (int)CommonEnum.SystemExcetion, context.Exception.Message));
                        }
                        //RedisCache.Instance.AddFailedAPI(value, context.HttpContext.Request.Path, msg, error, paramter);
                        return;
                    case ObjectResult objectResult:
                        context.Result =
                            new ObjectResult(new ResultObject(1, (int)CommonEnum.Succefull, objectResult.Value));
                        break;
                    case CommonObjectResult commonObject:
                        context.Result = new ObjectResult(commonObject.Value);
                        break;
                    case PagedObjectResult pagedObject:
                        context.Result = new ObjectResult(new PagedResult(1, CommonEnum.Succefull, pagedObject.data,
                            pagedObject.total, pagedObject.page, pagedObject.pagesize));
                        break;
                    case PagedLongTotalObjectResult pagedObject:
                        context.Result = new ObjectResult(new PagedLongTotalResult(1, CommonEnum.Succefull, pagedObject.data,
                            pagedObject.total, pagedObject.page, pagedObject.pagesize));
                        break;
                    case OtherObjectResult otherOject:
                        context.Result = new ObjectResult(otherOject);
                        break;
                    case ContentResult contentResult:
                        context.Result = contentResult;
                        break;
                    default:
                        context.Result = new ObjectResult(new ResultObject(1, (int)CommonEnum.Fail, null));
                        break;
                }
            }

            //Reset time && API成功计数设置
            RedisCache.Instance.ResetToken(value, context.HttpContext.Request.Path);
        }

        private string GetParameter(ActionExecutedContext context)
        {
            var parameter = string.Empty;
            switch (context.HttpContext.Request.Method)
            {
                case "GET":
                    if (context.HttpContext.Request.QueryString.HasValue)
                    {
                        parameter = context.HttpContext.Request.QueryString.Value;
                    }
                    break;
                case "POST": //如果加上[FromBody]，需要把参数传递过来
                    break;
                default:
                    break;
            }

            return parameter;
        }

        /// <summary>
        /// 判断控制器和Action是否要进行拦截
        /// </summary>
        /// <param name="actionContext"></param>
        /// <returns></returns>
        private static bool SkipResult(ActionExecutedContext actionContext)
        {
            return actionContext.ActionDescriptor.FilterDescriptors.Any(q => q.Filter.GetType() == typeof(NoResultFilter));
        }

        public class ResultObject
        {
            public int ret { get; set; }

            public int msg { get; set; }

            public object data { get; set; }

            public ResultObject(int returnValue, int message, object dataobj)
            {
                ret = returnValue;
                msg = message;
                data = dataobj;
            }
        }

        public class ClientObject
        {
            public int ret { get; set; }

            public int msg { get; set; }

            public object data { get; set; }

            public ClientObject(int returnValue, int message, object dataobj)
            {
                ret = returnValue;
                msg = message;
                data = dataobj;
            }
        }

        public class ClientDeviceObject
        {
            public int ret { get; set; }

            public string msg { get; set; }

            public object data { get; set; }

            public ClientDeviceObject(int returnValue, string message, object dataobj)
            {
                ret = returnValue;
                msg = message;
                data = dataobj;
            }
        }

        public class PagedResult: ResultObject
        {
            public int total { get; set; }

            public int page { get; set; }

            public int pagesize { get; set; }

            public PagedResult(int returnValue, Enum message, object dataobj, 
                int totalValue, int pageValue, int pagesizeValue) : base(returnValue, (int)Convert.ChangeType(message, typeof(int)), dataobj)
            {
                total = totalValue;
                page = pageValue;
                pagesize = pagesizeValue;
            }
        }

        public class PagedLongTotalResult : ResultObject
        {
            public long total { get; set; }

            public int page { get; set; }

            public int pagesize { get; set; }

            public PagedLongTotalResult(int returnValue, Enum message, object dataobj,
                long totalValue, int pageValue, int pagesizeValue) : base(returnValue,  (int)Convert.ChangeType(message, typeof(int)), dataobj)
            {
                total = totalValue;
                page = pageValue;
                pagesize = pagesizeValue;
            }
        }
    }
}
