
using DFS.Core.Abstractions.Exceptions;
using DFS.Core.Abstractions.View;
using DFS.Core.Mvc.Results;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;

namespace DFS.Core.Mvc
{
    /// <summary>
    /// 异常错误处理过滤器
    /// </summary>
    public class ServiceExceptionFilter : IExceptionFilter, IAsyncExceptionFilter
    {
        /////// <summary>
        /////// 主机环境设置 
        /////// </summary>
        //private readonly IWebHostEnvironment _hostingEnvironment;
        /// <summary>
        /// 日志
        /// </summary>
        private readonly ILogger _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="hostingEnvironment">环境变量配置</param>
        /// <param name="loggerFactory">日志工厂</param>
        public ServiceExceptionFilter( ILoggerFactory loggerFactory)
        {
           
            _logger = loggerFactory.CreateLogger<ServiceExceptionFilter>();
        }

        /// <summary>
        /// 发生异常时执行
        /// </summary>
        /// <param name="context">异常上下文</param>
        public void OnException(ExceptionContext context)
        {
            string requestId = context.HttpContext.TraceIdentifier + new Random().Next(1000, 9999);
            if (context.HttpContext != null && context.HttpContext.Request != null && context.HttpContext.Request.Query != null && context.HttpContext.Request.Query.ContainsKey(Constants.REQUEST_ID_QUERY_KEY))
            {
                //Guid.TryParse(context.HttpContext.Request.Query[""][0], out requestId);
                var value = context.HttpContext.Request.Query[""][0];
                if (!string.IsNullOrWhiteSpace(value))
                {
                    requestId = context.HttpContext.Request.Query[""][0];
                }
            }
            object contentResult = null;
            if (context.ActionDescriptor is Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)
            {
                Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor controllerActionDescriptor = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;

                if (controllerActionDescriptor?.MethodInfo.ReturnType == typeof(bool))
                {
                    contentResult = default(bool);
                }
                if (controllerActionDescriptor?.MethodInfo.ReturnType == typeof(int))
                {
                    contentResult = int.MinValue;
                }
                if (controllerActionDescriptor?.MethodInfo.ReturnType == typeof(long))
                {
                    contentResult = long.MinValue;
                }
                if (controllerActionDescriptor?.MethodInfo.ReturnType == typeof(decimal))
                {
                    contentResult = decimal.MinValue;
                }
            }
            if (context.Exception is StandardException)
            {
                context.Result = BuidResult(context.Exception as StandardException, requestId, contentResult);
            }
            else if (context.Exception is BusinessException)
            {
                context.Result = BuidResult(context.Exception as BusinessException, requestId, contentResult);
            }
            else
            {
                //context.HttpContext.RequestServices.get
                //if (_hostingEnvironment.EnvironmentName == "Development")
                //{
                //    return;
                //}

                //var json = new JsonErrorResponse();

                //json.Message = context.Exception.Message;//错误信息
                
                context.Result = BuidResult(new SystemErrorException(context.Exception==null?new Exception() : context.Exception), requestId, contentResult);

            }
            //异常已处理
            context.ExceptionHandled = true;
        }

        /// <summary>
        /// 异步发生异常时执行
        /// </summary>
        /// <param name="context">异常上下文</param>
        /// <returns></returns>
        public Task OnExceptionAsync(ExceptionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            OnException(context);
            return Task.CompletedTask;
        }

        /// <summary>
        ///  构造标准输出对象
        /// </summary>
        /// <param name="exception">微服务异常基类</param>
        /// <param name="requestId"></param>
        /// <param name="contentResult"></param>
        /// <returns></returns>
        private StandardObjectResult BuidResult(MicroServiceException exception, string requestId, object contentResult = null)
        {

            return new StandardObjectResult(new ServiceProtocol()
            {
                StatusCode = exception.StatusCode,
                Content = contentResult,
                RequestId = requestId,
                Notification = exception.InnerException != null ? exception.InnerException.Message : exception.Notification
            });
        }


        /// <summary>
        /// 自定义返回格式
        /// </summary>
        /// <param name="throwMsg"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        public string WriteLog(string throwMsg, Exception ex)
        {
            return string.Format("\r\n【自定义错误】：{0} \r\n【异常类型】：{1} \r\n【异常信息】：{2} \r\n【堆栈调用】：{3}", new object[] { throwMsg,
                ex.GetType().Name, ex.Message, ex.StackTrace });
        }

        public class InternalServerErrorObjectResult : ObjectResult
        {
            public InternalServerErrorObjectResult(object value) : base(value)
            {
                StatusCode = StatusCodes.Status500InternalServerError;
            }
        }
        //返回错误信息
        public class JsonErrorResponse
        {
            /// <summary>
            /// 生产环境的消息
            /// </summary>
            public string Message { get; set; }
            /// <summary>
            /// 开发环境的消息
            /// </summary>
            public string DevelopmentMessage { get; set; }
        }
    }
}
