namespace Common.system
{
    using Newtonsoft.Json.Linq;

    using System;
    using System.Collections.Specialized;
    using System.IO;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Threading;

    public class ZHttpUtil
    {
        public static string tokenKey = "";
        public static string tokenValue = "";
        public static string userId = "";
        public static string version = "";
        public static bool isSt;

        private static bool CheckValidationResult
        (
            object sender,
            X509Certificate certificate,
            X509Chain chain,
            SslPolicyErrors errors
        )
        {
            return true; //总是接受
        }

        public static HttpWebRequest GetHttpWebRequest(string url)
        {
            HttpWebRequest request;
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
                request = WebRequest.Create(url) as HttpWebRequest;
                if (request != null)
                {
                    request.ProtocolVersion = HttpVersion.Version10;
                }
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }
            return request;
        }

        public static WebResponse Download
        (
            string downloadUrl,
            long from,
            long to,
            string method
        )
        {
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    HttpWebRequest request = GetHttpWebRequest(downloadUrl);
                    request.Accept = "text/json,*/*;q=0.5";
                    request.AutomaticDecompression = DecompressionMethods.GZip;
                    request.AddRange(from, to);
                    request.Headers.Add("Accept-Charset", "utf-8;q=0.7,*;q=0.7");
                    request.Headers.Add("Accept-Encoding", "gzip, deflate, x-gzip, identity; q=0.9");
                    request.AutomaticDecompression = System.Net.DecompressionMethods.GZip;
                    request.Timeout = 120000;
                    request.Method = method;
                    request.KeepAlive = false;
                    request.ContentType = "application/json; charset=utf-8";
                    return request.GetResponse();
                }
                catch (Exception)
                {
                    Thread.Sleep(100);
                }
            }
            throw new Exception("已断开网络！请检查网络连接后重试下载！");
        }

        private static void AddHeader(HttpWebRequest webRequest)
        {
            webRequest.Headers.Add("Xh-St", isSt ? "true" : "false");
            if (!string.IsNullOrEmpty(tokenKey) && !string.IsNullOrEmpty(tokenValue))
            {
                webRequest.Headers.Add("Xh-Token-Key", tokenKey);
                webRequest.Headers.Add("Xh-Token-Value", tokenValue);
            }
            if (!string.IsNullOrEmpty(userId))
            {
                webRequest.Headers.Add("Xh-User-Id", userId);
            }
            webRequest.Headers.Add("Xh-Device", "microlecture_pc_t");
            webRequest.Headers.Add("Xh-Version", version);
        }

        ///  <summary>
        /// 调用Post接口
        ///  </summary>
        ///  <returns></returns>
        public static string PostStr
        (
            string url,
            string postData,
            bool jm = true,
            string contentType = "application/json"
        )
        {
            Stream responseStream = null;
            try
            {
                HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
                webRequest.Method = "POST";
                webRequest.Accept = "text/html,application/xhtml+xml,*/*";
                webRequest.ContentType = contentType + ";" + "UTF-8";
                Console.WriteLine(@"postData:" + postData);
                string aesPostData = postData;
                if (jm)
                {
                    if (isSt)
                    {
                        aesPostData = AesHelper.AesEncrypt(postData, "XINGHUOLIAOYUAN7");
                    }
                    AddHeader(webRequest);
                    Console.WriteLine(@"加密再解密后:" + AesHelper.AesDecrypt(aesPostData, "XINGHUOLIAOYUAN7"));
                }
                byte[] buffer = Encoding.UTF8.GetBytes(aesPostData);
                webRequest.ContentLength = buffer.Length;
                webRequest.GetRequestStream().Write(buffer, 0, buffer.Length);
                HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
                //只有可能需要加密的接口的响应头才处理
                if (jm)
                {
                    isSt = webResponse.GetResponseHeader("Xh-St") == "true";
                }
                responseStream = webResponse.GetResponseStream();
                if (responseStream == null) { return ""; }
                using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
            catch (Exception)
            {
                return "";
            }
            finally
            {
                if (responseStream != null)
                {
                    responseStream.Dispose();
                }
            }
        }

        /// <summary>
        /// Post Http请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="postData">传输数据</param>
        /// <param name="jm">加密</param>
        /// <param name="timeout">超时时间</param>
        /// <param name="contentType">媒体格式</param>
        /// <param name="encode">编码</param>
        /// <returns>泛型集合</returns>
        public static T PostSignle<T>
        (
            string url,
            string postData = "",
            bool jm = true,
            int timeout = 5000,
            string contentType = "application/json;",
            string encode = "UTF-8"
        ) where T : class
        {
            if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && postData != null)
            {
                try
                {
                    string respstr = PostStr(
                        url,
                        postData,
                        jm,
                        contentType
                    );
                    return JsonHelper.JsonToObj<T>(respstr);
                }
                catch (Exception)
                {
                    // ignored
                }
            }
            return default;
        }

        /// <summary>
        /// HttpWebRequest 下载
        /// </summary>
        /// <param name="url">URI</param>
        /// <param name="filePath"></param>
        /// <param name="header"></param>
        /// <returns></returns>
        public static bool DownloadFile(string url, string filePath, string header)
        {
            try
            {
                HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);

                //httpWebRequest.ContentType = "application/x-www-form-urlencoded";
                httpWebRequest.Method = "GET";
                //httpWebRequest.ContentType = "image/jpeg";
                //对发送的数据不使用缓存
                httpWebRequest.AllowWriteStreamBuffering = false;
                //httpWebRequest.Timeout = 300000;
                httpWebRequest.ServicePoint.Expect100Continue = false;
                WebHeaderCollection myWebHeaderCollection = httpWebRequest.Headers;
                //myWebHeaderCollection.Add("Accept", "*/*");
                if (header != "")
                {
                    myWebHeaderCollection.Add("access_token:" + header);
                }
                HttpWebResponse webRespon = (HttpWebResponse)httpWebRequest.GetResponse();
                Stream webStream = webRespon.GetResponseStream();
                if (webStream == null)
                {
                    return false;
                }
                Stream stream = new FileStream(
                    filePath,
                    FileMode.Create,
                    FileAccess.ReadWrite,
                    FileShare.ReadWrite
                );
                byte[] bArr = new byte[1024];
                int size = webStream.Read(bArr, 0, bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = webStream.Read(bArr, 0, bArr.Length);
                    //M_DownloadInfo.downloadCount = M_DownloadInfo.downloadCount + 1;
                }
                webRespon.Close();
                stream.Close();
                webStream.Close();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 上传文件流
        /// 创建人：赵耀
        /// 创建时间：2020年9月5日
        /// </summary>
        /// <param name="url">URL</param>
        /// <param name="databyte">文件数据流</param>
        /// <param name="filename">文件名</param>
        /// <param name="formFields">参数 可不传</param>
        public static JObject UploadFile
        (
            string url,
            byte[] databyte,
            string filename,
            NameValueCollection formFields = null
        )
        {
            // 时间戳，用做boundary
            string boundary = "-----" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            //根据uri创建HttpWebRequest对象
            HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(url));
            httpReq.ContentType = "multipart/form-data; boundary=" + boundary;
            httpReq.Method = "POST";
            httpReq.KeepAlive = true;
            //httpReq.Timeout = 300000;
            //httpReq.AllowWriteStreamBuffering = false; //对发送的数据不使用缓存
            httpReq.Credentials = CredentialCache.DefaultCredentials;
            try
            {
                Stream postStream = httpReq.GetRequestStream();
                //参数
                const string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                if (formFields != null)
                {
                    foreach (string key in formFields.Keys)
                    {
                        postStream.Write(boundarybytes, 0, boundarybytes.Length);
                        string formitem = string.Format(formdataTemplate, key, formFields[key]);
                        byte[] formitembytes = Encoding.UTF8.GetBytes(formitem);
                        postStream.Write(formitembytes, 0, formitembytes.Length);
                    }
                }
                postStream.Write(boundarybytes, 0, boundarybytes.Length);
                const string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";

                //文件头
                string header = string.Format(headerTemplate, "file", filename);
                byte[] headerbytes = Encoding.UTF8.GetBytes(header);
                postStream.Write(headerbytes, 0, headerbytes.Length);

                //文件流
                postStream.Write(databyte, 0, databyte.Length);

                //结束边界
                byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                postStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                postStream.Close();

                //获取服务器端的响应
                JObject jobResult = null;
                using (HttpWebResponse response = (HttpWebResponse)httpReq.GetResponse())
                {
                    Stream receiveStream = response.GetResponseStream();
                    if (receiveStream != null)
                    {
                        StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
                        string returnValue = readStream.ReadToEnd();
                        jobResult = JObject.Parse(returnValue);
                        response.Close();
                        readStream.Close();
                    }
                }
                return jobResult;
            }
            catch (Exception ex)
            {
                LogHelper.Logerror.Error("【文件上传】" + ex.Message, ex);
                return null;
            }
        }

        /// <summary>
        /// 获取公网IP和地址，失败则获取局域网IP
        /// </summary>
        /// <param name="addressIp">IP地址</param>
        /// <param name="address">地址</param>
        /// <returns></returns>
        public static bool GetAddressIp(out string addressIp, out string address)
        {
            addressIp = "";
            address = "";
            try
            {
                //请求搜狐获取公网IP，获取失败后获取局域网IP
                WebRequest request = WebRequest.Create("http://pv.sohu.com/cityjson?ie=utf-8");
                request.Timeout = 10000;
                WebResponse response = request.GetResponse();
                Stream resStream = response.GetResponseStream();
                if (resStream != null)
                {
                    StreamReader sr = new StreamReader(resStream, System.Text.Encoding.UTF8);
                    string htmlinfo = sr.ReadToEnd();
                    string jsonStr = htmlinfo.Substring(htmlinfo.IndexOf("{", StringComparison.Ordinal), htmlinfo.LastIndexOf("}", StringComparison.Ordinal) - htmlinfo.IndexOf("{", StringComparison.Ordinal) + 1);
                    JObject obj = JObject.Parse(jsonStr);
                    addressIp = obj["cip"]?.ToString();
                    address = obj["cname"]?.ToString();
                    resStream.Close();
                    sr.Close();
                }
                return true;
            }
            catch (Exception)
            {
                //获取本地局域网IP
                foreach (System.Net.IPAddress ipAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
                {
                    if (ipAddress.AddressFamily.ToString() == "InterNetwork")
                    {
                        addressIp = ipAddress.ToString();
                    }
                }
                return false;
            }
        }
    }
}