using HttpWebAdapters;
using HttpWebAdapters.Adapters;
using SolrNet;
using SolrNet.Exceptions;
using SolrNet.Impl;
using SolrNet.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace DapperORM
{
    /// <summary>
    /// solr POST方法
    /// </summary>
    public class PostSolrConnection : SolrConnection, ISolrConnection
    {
        /// <summary>
        /// 版本
        /// </summary>
        private const string _Version = "2.2";

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serverURL">服务地址</param>
        public PostSolrConnection(string serverURL) : base(serverURL)
        {
            ServerURL = serverURL;
            Timeout = -1;
            Cache = new NullCache();
            HttpWebRequestFactory = new HttpWebRequestFactory();
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="relativeUrl">相对路径</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public new string Get(string relativeUrl, IEnumerable<KeyValuePair<string, string>> parameters)
        {
            var u = new UriBuilder(ServerURL);
            u.Path += relativeUrl;
            string postData = GetQuery(parameters);

            byte[] data = Encoding.UTF8.GetBytes(postData);
            var request = HttpWebRequestFactory.Create(u.Uri);
            request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
            request.Method = HttpWebRequestMethod.POST;
            request.KeepAlive = true;
            request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
            request.ContentLength = data.Length;
            using (
                Stream newStream = request.GetRequestStream())
            {
                newStream.Write(data, 0, data.Length);
            }

            var cached = Cache[u.Uri.ToString()];
            if (cached != null)
            {
                request.Headers.Add(HttpRequestHeader.IfNoneMatch, cached.ETag);
            }
            if (Timeout > 0)
            {
                request.ReadWriteTimeout = Timeout;
                request.Timeout = Timeout;
            }
            try
            {
                var response = GetResponse(request);
                if (response.ETag != null)
                    Cache.Add(new SolrCacheEntity(u.Uri.ToString(), response.ETag, response.Data));
                return response.Data;
            }
            catch (WebException e)
            {
                if (e.Response != null)
                {
                    using (e.Response)
                    {
                        var r = new HttpWebResponseAdapter(e.Response);
                        if (r.StatusCode == HttpStatusCode.NotModified)
                        {
                            return cached.Data;
                        }
                        using (var s = e.Response.GetResponseStream())
                        using (var sr = new StreamReader(s))
                        {
                            throw new SolrConnectionException(sr.ReadToEnd(), e, u.Uri.ToString());
                        }
                    }
                }
                throw new SolrConnectionException(e, u.Uri.ToString());
            }
        }

        /// <summary>
        /// Gets the Query 
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private string GetQuery(IEnumerable<KeyValuePair<string, string>> parameters)
        {
            var param = new List<KeyValuePair<string, string>>();
            if (parameters != null)
                param.AddRange(parameters);

            param.Add(KV.Create("version", _Version));
            return string.Join("&", param
                .Select(kv => KV.Create(HttpUtility.UrlEncode(kv.Key), HttpUtility.UrlEncode(kv.Value)))
                .Select(kv => string.Format("{0}={1}", kv.Key, kv.Value))
                .ToArray());
        }



        /// <summary>
        /// Gets http response, returns (etag, data)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private SolrResponse GetResponse(IHttpWebRequest request)
        {
            using (var response = request.GetResponse())
            {
                var etag = response.Headers[HttpResponseHeader.ETag];
                var cacheControl = response.Headers[HttpResponseHeader.CacheControl];
                if (cacheControl != null && cacheControl.Contains("no-cache"))
                    etag = null; // avoid caching things marked as no-cache

                return new SolrResponse(etag, ReadResponseToString(response));
            }
        }

        /// <summary>
        /// Reads the full stream from the response and returns the content as stream,
        /// using the correct encoding.
        /// </summary>
        /// <param name="response">Web response from request to Solr</param>
        /// <returns></returns>
        private string ReadResponseToString(IHttpWebResponse response)
        {
            using (var responseStream = response.GetResponseStream())
            using (var reader = new StreamReader(responseStream, TryGetEncoding(response)))
            {
                return reader.ReadToEnd();
            }
        }

        private struct SolrResponse
        {
            public string ETag { get; private set; }
            public string Data { get; private set; }
            public SolrResponse(string eTag, string data) : this()
            {
                ETag = eTag;
                Data = data;
            }
        }
        private Encoding TryGetEncoding(IHttpWebResponse response)
        {
            try
            {
                return Encoding.GetEncoding(response.CharacterSet);
            }
            catch
            {
                return Encoding.UTF8;
            }
        }


    }
}
