using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Yarp.ReverseProxy.Forwarder;
namespace FastGithub.ReverseProxy
{
    /// 
    /// 反向代理中间件
    /// 
    sealed class ReverseProxyMiddleware
    {
        private readonly IHttpForwarder httpForwarder;
        private readonly SniHttpClientHanlder sniHttpClientHanlder;
        private readonly NoSniHttpClientHanlder noSniHttpClientHanlder;
        private readonly FastGithubConfig fastGithubConfig;
        private readonly ILogger logger;
        public ReverseProxyMiddleware(
            IHttpForwarder httpForwarder,
            SniHttpClientHanlder sniHttpClientHanlder,
            NoSniHttpClientHanlder noSniHttpClientHanlder,
            FastGithubConfig fastGithubConfig,
            ILogger logger)
        {
            this.httpForwarder = httpForwarder;
            this.sniHttpClientHanlder = sniHttpClientHanlder;
            this.noSniHttpClientHanlder = noSniHttpClientHanlder;
            this.fastGithubConfig = fastGithubConfig;
            this.logger = logger;
        }
        /// 
        /// 处理请求
        /// 
        /// 
        /// 
        public async Task InvokeAsync(HttpContext context)
        {
            var host = context.Request.Host.Host;
            if (this.fastGithubConfig.TryGetDomainConfig(host, out var domainConfig) == false)
            {
                await context.Response.WriteAsJsonAsync(new
                {
                    error = ForwarderError.NoAvailableDestinations.ToString(),
                    message = $"不支持https反向代理{host}这个域名"
                });
                return;
            }
            var destinationPrefix = GetDestinationPrefix(host, domainConfig.Destination);
            var requestConfig = new ForwarderRequestConfig { Timeout = domainConfig.Timeout };
            var httpClient = domainConfig.TlsSni
               ? new HttpMessageInvoker(this.sniHttpClientHanlder, disposeHandler: false)
               : new HttpMessageInvoker(this.noSniHttpClientHanlder, disposeHandler: false);
            var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient, requestConfig);
            await ResponseErrorAsync(context, error);
        }
        /// 
        /// 获取目标前缀
        /// 
        ///  
        /// 
        /// 
        private string GetDestinationPrefix(string host, Uri? destination)
        {
            var defaultValue = $"https://{host}/";
            if (destination == null)
            {
                return defaultValue;
            }
            var baseUri = new Uri(defaultValue);
            var result = new Uri(baseUri, destination).ToString();
            this.logger.LogInformation($"[{defaultValue}->{result}]");
            return result;
        }
        /// 
        /// 写入错误信息
        /// 
        /// 
        /// 
        /// 
        private static async Task ResponseErrorAsync(HttpContext context, ForwarderError error)
        {
            if (error == ForwarderError.None)
            {
                return;
            }
            var errorFeature = context.GetForwarderErrorFeature();
            if (errorFeature == null)
            {
                return;
            }
            await context.Response.WriteAsJsonAsync(new
            {
                error = error.ToString(),
                message = errorFeature.Exception?.Message
            });
        }
    }
}