using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace FastGithub.ReverseProxy
{
    /// 
    /// 请求日志中间件
    /// 
    sealed class RequestLoggingMiddleware
    {
        private readonly ILogger logger;
        /// 
        /// 请求日志中间件
        /// 
        /// 
        public RequestLoggingMiddleware(ILogger logger)
        {
            this.logger = logger;
        }
        /// 
        /// 执行请求
        /// 
        /// 
        /// 
        /// 
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            var stopwatch = Stopwatch.StartNew();
            try
            {
                await next(context);
            }
            finally
            {
                stopwatch.Stop();
            }
            var request = context.Request;
            var response = context.Response;
            var message = $"{request.Method} {request.Scheme}://{request.Host}{request.Path} responded {response.StatusCode} in {stopwatch.Elapsed.TotalMilliseconds} ms";
            var client = context.Connection.RemoteIpAddress;
            if (IPAddress.Loopback.Equals(client) == false)
            {
                message = $"{client} {message}";
            }
            var exception = context.GetForwarderErrorFeature()?.Exception;
            if (exception == null)
            {
                this.logger.LogInformation(message);
            }
            else if (IsError(exception))
            {
                this.logger.LogError($"{message}{Environment.NewLine}{exception}");
            }
            else
            {
                this.logger.LogWarning($"{message}{Environment.NewLine}{GetMessage(exception)}");
            }
        }
        /// 
        /// 是否为错误
        /// 
        /// 
        /// 
        private static bool IsError(Exception exception)
        {
            if (exception is OperationCanceledException)
            {
                return false;
            }
            if (exception is IOException ioException && ioException.InnerException is ConnectionAbortedException)
            {
                return false;
            }
            return true;
        }
        /// 
        /// 获取异常信息
        /// 
        /// 
        /// 
        private static string GetMessage(Exception exception)
        {
            var ex = exception;
            var builder = new StringBuilder();
            while (ex != null)
            {
                var type = ex.GetType();
                builder.Append(type.Namespace).Append(".").Append(type.Name).Append(": ").AppendLine(ex.Message);
                ex = ex.InnerException;
            }
            return builder.ToString();
        }
    }
}