using Newtonsoft.Json;
using Serilog.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
using XYY.Core.Standard.TitaniumWebProxy.Model;

namespace XYY.Core.Standard.TitaniumWebProxy
{
    public class TitaniumClient
    {
        #region 构造
        private static Logger _logger;
        ProxyServer proxyServer;
        ExplicitProxyEndPoint explicitEndPoint;
        /// <summary>
        /// 不做使用，没有fiddler好用
        /// 数据获取过程中需要做较多空值判断与处理
        /// </summary>
        /// <param name="logger"></param>
        [Obsolete("没有fiddler好用")]
        public TitaniumClient(Logger logger) {
            _logger = logger;
            proxyServer = new ProxyServer();
            explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, ListenPort, true)
            {
                // 在所有https请求上使用自颁发的通用证书
                // 通过不为每个启用http的域创建证书来优化性能
                // 当代理客户端不需要证书信任时非常有用
                //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
            };
            Startup();
        }
        #endregion
        #region 私有
        //监听端口，以及代理端口
        private const ushort ListenPort = 8877;
        private static List<string> _hosts = new List<string>() { "services.frayun.com", "ws.fedex.com:443" };
        /// <summary>
        /// 证书的处理
        /// </summary>
        private void EnsureRootCertificate()
        {
            proxyServer.CertificateManager.CertificateEngine = Titanium.Web.Proxy.Network.CertificateEngine.DefaultWindows;
            proxyServer.CertificateManager.EnsureRootCertificate();
        }
        /// <summary>
        /// 事件处理
        /// </summary>
        private void AddAttachEventListeners()
        {
            proxyServer.BeforeRequest += OnRequest;
            proxyServer.BeforeResponse += OnResponse;
            proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
            proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
        }
        private void CutAttachEventListeners()
        {
            proxyServer.BeforeRequest -= OnRequest;
            proxyServer.BeforeResponse -= OnResponse;
            proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
            proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection;
        }
        /// <summary>
        /// 命中请求
        /// 判断是否需要捕获
        /// </summary>
        /// <param name="oSession"></param>
        /// <returns></returns>
        private bool isHitRequestFun(SessionEventArgs e)
        {
            var isHitRequest = false;
            if (_hosts.Any(x => x.Contains(e.HttpClient.Request.Host)))   // url
            {
                isHitRequest = true;
            }
            return isHitRequest;
        }
        private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
        {
            //await Task.Run(() =>
            //{
            //    string hostname = e.HttpClient.Request.RequestUri.Host;
            //    if (hostname.Contains("fedex.com"))
            //    {
            //        // 排除不想代理的Https地址
            //        // 对于使用证书固定的客户端很有用
            //        // for example dropbox.com
            //        e.DecryptSsl = false;
            //    }
            //});
        }
        /// <summary>
        /// 请求时发送
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public async Task OnRequest(object sender, SessionEventArgs e)
        {
            //var requestHeaders = e.HttpClient.Request.Headers;
            //var method = e.HttpClient.Request.Method.ToUpper();
            //if (isHitRequestFun(e))//(method == "POST" || method == "PUT" || method == "PATCH")
            //{
            //    //// Get/Set request body bytes
            //    //byte[] bodyBytes = await e.GetRequestBody();
            //    //e.SetRequestBody(bodyBytes);
            //    //// Get/Set request body as string
            //    //string bodyString = await e.GetRequestBodyAsString();
            //    //e.SetRequestBodyString(bodyString);
            //    // store request 
            //    // 这样你就能从响应处理器中找到它
            //    e.UserData = e.HttpClient.Request;
            //}
            //// 取消带有自定义HTML内容的请求
            //// Filter URL
            //if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("google.com"))
            //{
            //    e.Ok("<!DOCTYPE html>" +
            //        "<html><body><h1>" +
            //        "Website Blocked" +
            //        "</h1>" +
            //        "<p>Blocked by titanium web proxy.</p>" +
            //        "</body>" +
            //        "</html>");
            //}
            //// Redirect example
            //if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
            //{
            //    e.Redirect("https://www.paypal.com");
            //}
        }
        /// <summary>
        /// 返回数据处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public async Task OnResponse(object sender, SessionEventArgs e)
        {
            if (isHitRequestFun(e))
            {
                logData(e);
            }
            //// read response headers
            //var responseHeaders = e.HttpClient.Response.Headers;
            ////if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
            //if (e.HttpClient.Request.Method == "GET" || e.HttpClient.Request.Method == "POST")
            //{
            //    if (e.HttpClient.Response.StatusCode == 200)
            //    {
            //        if (e.HttpClient.Response.ContentType != null && e.HttpClient.Response.ContentType.Trim().ToLower().Contains("text/html"))
            //        {
            //            byte[] bodyBytes = await e.GetResponseBody();
            //            e.SetResponseBody(bodyBytes);
            //            string body = await e.GetResponseBodyAsString();
            //            e.SetResponseBodyString(body);
            //        }
            //    }
            //}
            //if (e.UserData != null)
            //{
            //    // 从存储在RequestHandler中的UserData属性的访问请求
            //    var request = (Request)e.UserData;
            //}
        }
        /// <summary>
        /// 允许重写默认的证书验证逻辑
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
        {
            // 根据证书错误，设置IsValid为真/假
            if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
                e.IsValid = true;
            return Task.CompletedTask;
        }
        /// <summary>
        /// 允许在相互身份验证期间重写默认客户端证书选择逻辑
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)
        {
            // set e.clientCertificate to override
            return Task.CompletedTask;
        }
        #endregion
        /// <summary>
        /// 退出
        /// </summary>
        public void Quit()
        {
            CutAttachEventListeners();
            proxyServer.Stop();
        }
        public void Startup()
        {
            EnsureRootCertificate();
            AddAttachEventListeners();
            proxyServer.AddEndPoint(explicitEndPoint);
            proxyServer.Start();
            //设置系统代理
            //proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
            //proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);

        }
        #region 数据落地
        private static void logData(SessionEventArgs e)
        {
            TitaniumMessage titaniumMessage = new TitaniumMessage()
            {
                Methods = e.HttpClient.Request.Method.ToUpper(),
                FullUrl = e.HttpClient.Request.Url,
                ServerConnectionId = e.ServerConnectionId.ToString(),
                ClientConnectionId = e.ClientConnectionId.ToString(),
                HostName = e.HttpClient.Request.Host,
                RequestHeader = e.HttpClient.Request.HeaderText,
                RequestBody = e.HttpClient.Request.BodyString,//需要做空判断，否则报错
                ResponseHeader = e.HttpClient.Response.HeaderText,
                ResponseBody = e.HttpClient.Response.BodyString,
            };
            _logger.Warning(JsonConvert.SerializeObject(titaniumMessage));
        }
        #endregion
    }
}
