using Newtonsoft.Json.Linq;

using System;
using System.Collections.Generic;
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;

namespace Common.system
{
    /// <summary>
    /// HttpHelper
    /// 创建人：赵耀
    /// </summary>
    public class HttpHelper
    {
        public static void init_Request(ref System.Net.HttpWebRequest request)
        {
            request.Accept = "text/json,*/*;q=0.5";
            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 = 8000;
        }

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

        public static System.Net.HttpWebRequest GetHttpWebRequest(string url)
        {
            HttpWebRequest request = null;
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                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 = HttpHelper.GetHttpWebRequest(downloadUrl);
                    HttpHelper.init_Request(ref request);
                    request.Accept = "text/json,*/*;q=0.5";
                    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("已断开网络！请检查网络连接后重试下载！");
        }

        public static string Get(string url, IDictionary<string, string> param)
        {
            List<string> paramBuilder = new List<string>();
            foreach (KeyValuePair<string, string> item in param)
            {
                paramBuilder.Add(string.Format("{0}={1}", item.Key, item.Value));
            }
            url = string.Format("{0}?{1}", url.TrimEnd('?'), string.Join(",", paramBuilder.ToArray()));
            return Get(url);
        }

        public static string Get(string url)
        {
            try
            {
                HttpWebRequest request = GetHttpWebRequest(url);
                if (request != null)
                {
                    string retval = null;
                    init_Request(ref request);
                    using (WebResponse Response = request.GetResponse())
                    {
                        using (StreamReader reader = new System.IO.StreamReader(Response.GetResponseStream(), System.Text.Encoding.UTF8))
                        {
                            retval = reader.ReadToEnd();
                        }
                    }
                    return retval;
                }
            }
            catch
            {
            }
            return null;
        }

        public static string Post(string url, string data)
        {
            try
            {
                HttpWebRequest request = GetHttpWebRequest(url);
                if (request != null)
                {
                    string retval = null;
                    init_Request(ref request);
                    request.Method = "POST";
                    request.ServicePoint.Expect100Continue = false;
                    request.ContentType = "application/json; charset=utf-8";
                    request.Timeout = 5000;
                    byte[] bytes = System.Text.UTF8Encoding.UTF8.GetBytes(data);
                    request.ContentLength = bytes.Length;
                    using (Stream stream = request.GetRequestStream())
                    {
                        stream.Write(bytes, 0, bytes.Length);
                    }
                    using (WebResponse response = request.GetResponse())
                    {
                        using (StreamReader reader = new System.IO.StreamReader(response.GetResponseStream()))
                        {
                            retval = reader.ReadToEnd();
                        }
                    }
                    return retval;
                }
            }
            catch
            {
            }
            return null;
        }

        /// <summary>
        ///调用Post接口
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static string HttpPost(string body, string Url)
        {
            try
            {
                Encoding encoding = Encoding.UTF8;

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
                request.Method = "POST";
                request.Accept = "text/html,application/xhtml+xml,*/*";
                request.ContentType = "application/json";

                string postDataAES = body;
                bool IsParameterEncryption = FileToolsCommon.GetConfigValue("IsParameterEncryption") != "0";
                if (IsParameterEncryption)
                {
                    postDataAES = AESHelper.AESEncrypt(body, "XINGHUOLIAOYUAN7");
                }

                byte[] buffer = encoding.GetBytes(postDataAES);
                request.ContentLength = buffer.Length;
                request.GetRequestStream().Write(buffer, 0, buffer.Length);

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                // LogHelper.Instance.Debug($"POST接口连接失败，请求参数：{ex.Message}");
                return "POST报错:" + ex.Message;
            }
        }

        /// <summary>
        /// Post Http请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="postData">传输数据</param>
        /// <param name="timeout">超时时间</param>
        /// <param name="contentType">媒体格式</param>
        /// <param name="encode">编码</param>
        /// <returns>泛型集合</returns>
        public static T PostAndRespSignle<T>(string url, int timeout = 5000, string postData = "", string contentType = "application/json;", string encode = "UTF-8") where T : class
        {
            if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && postData != null)
            {
                // webRequest.Headers.Add("Authorization", "Bearer " + "SportApiAuthData");
                HttpWebResponse webResponse = null;
                Stream responseStream = null;
                Stream requestStream = null;
                StreamReader streamReader = null;
                try
                {
                    string postDataAES = postData;
                    bool IsParameterEncryption = FileToolsCommon.GetConfigValue("IsParameterEncryption") != "0";
                    if (IsParameterEncryption)
                    {
                        postDataAES = AESHelper.AESEncrypt(postData, "XINGHUOLIAOYUAN7");
                    }
                    string respstr = GetStreamReader(url, responseStream, requestStream, streamReader, webResponse, timeout, encode, postDataAES, contentType);
                    return JsonHelper.JsonToObj<T>(respstr);
                }
                catch (Exception)
                {
                }
                finally
                {
                    if (responseStream != null)
                    {
                        responseStream.Dispose();
                    }

                    if (webResponse != null)
                    {
                        webResponse.Close();
                    }

                    if (requestStream != null)
                    {
                        requestStream.Dispose();
                    }

                    if (streamReader != null)
                    {
                        streamReader.Dispose();
                    }
                }
            }
            return default(T);
        }

        private static string GetStreamReader(string url, Stream responseStream, Stream requestStream, StreamReader streamReader, WebResponse webResponse, int timeout, string encode, string postData, string contentType)
        {
            try
            {
                byte[] data = Encoding.GetEncoding(encode).GetBytes(postData);
                HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
                webRequest.Method = "POST";
                webRequest.ContentType = contentType + ";" + encode;
                webRequest.ContentLength = data.Length;
                webRequest.Timeout = timeout;
                requestStream = webRequest.GetRequestStream();
                requestStream.Write(data, 0, data.Length);
                webResponse = (HttpWebResponse)webRequest.GetResponse();
                responseStream = webResponse.GetResponseStream();
                if (responseStream == null) { return ""; }
                streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encode));
                return streamReader.ReadToEnd();
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Cookie
        /// </summary>
        public static CookieContainer cc = new CookieContainer();

        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="serviceaddress">请求地址</param>
        /// <param name="strcontent">头</param>
        /// <param name="contenttype">参数</param>
        /// <param name="header">token</param>
        /// <returns></returns>
        public static JObject GetFunction(string serviceaddress, string strcontent, string contenttype, string header, int Timeout = 5000)
        {
            try
            {
                string serviceAddress = serviceaddress + strcontent;
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceAddress);
                WebHeaderCollection myWebHeaderCollection = request.Headers;
                request.CookieContainer = cc;
                if (header != "")
                {
                    myWebHeaderCollection.Add("access_token:" + header);
                }

                request.Method = "GET";
                request.ContentType = contenttype;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                string encoding = response.ContentEncoding;
                if (encoding == null || encoding.Length < 1)
                {
                    encoding = "UTF-8"; //默认编码
                }
                StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding));
                string retString = reader.ReadToEnd();

                //解析josn
                JObject jo = JObject.Parse(retString);
                return jo;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Post请求
        /// </summary>
        /// <param name="serviceaddress">请求地址</param>
        /// <param name="contenttype">头 application/x-www-form-urlencoded</param>
        /// <param name="strcontent">参数</param>
        /// <param name="header">token</param>
        /// <returns></returns>
        public static JObject PostFunction(string serviceaddress, string contenttype, string strcontent, string header, int Timeout = 5000)
        {
            try
            {
                string serviceAddress = serviceaddress;
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceAddress);
                WebHeaderCollection myWebHeaderCollection = request.Headers;

                request.CookieContainer = cc;
                //myWebHeaderCollection.Add("Accept", "*/*");
                if (header != "")
                {
                    myWebHeaderCollection.Add("access_token:" + header);
                }
                request.Timeout = Timeout;
                request.Method = "POST";
                request.ContentType = contenttype;
                using (StreamWriter dataStream = new StreamWriter(request.GetRequestStream()))
                {
                    dataStream.Write(strcontent);
                    dataStream.Close();
                }
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                string encoding = response.ContentEncoding;
                if (encoding == null || encoding.Length < 1)
                {
                    encoding = "UTF-8"; //默认编码
                }
                StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding));
                string retString = reader.ReadToEnd();
                retString = retString.Replace("\\r\\n", "");

                //解析josn
                JObject jo = JObject.Parse(retString);
                return jo;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLog("请求失败（若网络无问题，请重置winsock，解决方法：以管理员方式打开cmd执行 netsh winsock reset 后重启）", ex);
                return null;
            }
        }

        /// <summary>
        ///  上传方法
        /// </summary>
        /// <param name="url">webapi地址</param>
        /// <param name="files">本地文件路径，单文件默认为string[0]</param>
        /// <param name="token"></param>
        /// <param name="formFields">参数可不传</param>
        /// <returns></returns>
        public static JObject UploadFilesToRemoteUrl(string url, string[] files, string token, NameValueCollection formFields = null)
        {
            string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.ContentType = "multipart/form-data; boundary=" +
                                    boundary;
            request.Method = "POST";
            request.KeepAlive = true;

            Stream memStream = new System.IO.MemoryStream();

            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
                                                                    boundary + "\r\n");
            byte[] endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
                                                                        boundary + "--");
            WebHeaderCollection myWebHeaderCollection = request.Headers;
            request.CookieContainer = cc;
            if (token != "")
            {
                myWebHeaderCollection.Add("access_token:" + token);
            }

            string formdataTemplate = "\r\n--" + boundary +
                                        "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
            if (formFields != null)
            {
                foreach (string key in formFields.Keys)
                {
                    string formitem = string.Format(formdataTemplate, key, formFields[key]);
                    byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                    memStream.Write(formitembytes, 0, formitembytes.Length);
                }
            }

            string headerTemplate =
                "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
                "Content-Type: application/octet-stream\r\n\r\n";

            for (int i = 0; i < files.Length; i++)
            {
                memStream.Write(boundarybytes, 0, boundarybytes.Length);
                string header = string.Format(headerTemplate, "fileData", files[i]);
                byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);

                memStream.Write(headerbytes, 0, headerbytes.Length);

                using (FileStream fileStream = new FileStream(files[i], FileMode.Open, FileAccess.Read))
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead = 0;
                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        memStream.Write(buffer, 0, bytesRead);
                    }
                }
            }

            //memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
            request.ContentLength = memStream.Length;

            using (Stream requestStream = request.GetRequestStream())
            {
                memStream.Position = 0;
                byte[] tempBuffer = new byte[memStream.Length];
                memStream.Read(tempBuffer, 0, tempBuffer.Length);
                memStream.Close();
                requestStream.Write(tempBuffer, 0, tempBuffer.Length);
            }

            using (WebResponse response = request.GetResponse())
            {
                Stream stream2 = response.GetResponseStream();
                StreamReader reader2 = new StreamReader(stream2);
                JObject a = JObject.Parse(reader2.ReadToEnd());
                return a;
            }
        }

        /// <summary>
        /// HttpWebRequest 下载
        /// </summary>
        /// <param name="url">URI</param>
        /// <returns></returns>
        public static bool GetDataGetHtml(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();
                long length = webRespon.ContentLength;
                if (webStream == null)
                {
                    return false;
                }
                int lengthint = Convert.ToInt32(length);
                //int num = lengthint / 1024;
                //int count = 0;
                //M_DownloadInfo.totalCount = lengthint / 1024;
                //M_DownloadInfo.downloadCount = 0;

                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)
            {
                //LogHelper.WriteErrLog("请求失败：" + ex.Message, ex);
                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 UploadRequestflow(string url, byte[] databyte, string filename, NameValueCollection formFields = null)
        {
            JObject jobResult = 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();

                //获取服务器端的响应
                using (HttpWebResponse response = (HttpWebResponse)httpReq.GetResponse())
                {
                    Stream receiveStream = response.GetResponseStream();
                    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.WriteErrLog("【文件上传】" + ex.Message, ex);
                return null;
            }
            finally
            {
                httpReq = null;
            }
        }

        /// <summary>
        /// Post Http请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="postData"></param>
        /// <param name="timeout"></param>
        /// <param name="contentType"></param>
        /// <param name="encode"></param>
        /// <returns>响应流字符串</returns>
        public static string PostAndRespStr(string url, string postData = "", int timeout = 5000, string contentType = "application/json;", string encode = "UTF-8")
        {
            if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(encode) && !string.IsNullOrEmpty(contentType) && postData != null)
            {
                HttpWebResponse webResponse = null;
                Stream responseStream = null;
                Stream requestStream = null;
                StreamReader streamReader = null;
                try
                {
                    string postDataAES = postData;
                    bool IsParameterEncryption = FileToolsCommon.GetConfigValue("IsParameterEncryption") != "0";
                    if (IsParameterEncryption)
                    {
                        postDataAES = AESHelper.AESEncrypt(postData, "XINGHUOLIAOYUAN7");
                    }
                    return GetStreamReader(url, responseStream, requestStream, streamReader, webResponse, timeout, encode, postDataAES, contentType);
                }
                catch (Exception)
                {
                }
                finally
                {
                    if (responseStream != null)
                    {
                        responseStream.Dispose();
                    }

                    if (webResponse != null)
                    {
                        webResponse.Close();
                    }

                    if (requestStream != null)
                    {
                        requestStream.Dispose();
                    }

                    if (streamReader != null)
                    {
                        streamReader.Dispose();
                    }
                }
            }
            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();
                StreamReader sr = new StreamReader(resStream, System.Text.Encoding.UTF8);
                string htmlinfo = sr.ReadToEnd();
                string jsonStr = htmlinfo.Substring(htmlinfo.IndexOf("{"), htmlinfo.LastIndexOf("}") - htmlinfo.IndexOf("{") + 1);
                JObject obj = JObject.Parse(jsonStr);
                AddressIP = obj["cip"].ToString();
                Address = obj["cname"].ToString();
                resStream.Close();
                sr.Close();
                return true;
                //Regex r = new Regex("((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|[1-9])", RegexOptions.None);
                //Match mc = r.Match(htmlinfo);
                //AddressIP = mc.Groups[0].Value;
            }
            catch (Exception)
            {
                //获取本地局域网IP
                foreach (System.Net.IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
                {
                    if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                    {
                        AddressIP = _IPAddress.ToString();
                    }
                }
                return false;
            }
        }
    }
}