using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Net.Http.Formatting;


namespace WctCustomerApiSample.Api
{
    public class BaseService
    {
        private static readonly Lazy<HttpClientHandler> _lazy = new Lazy<HttpClientHandler>(() =>
        {
            // 為了開啟cookie，讓web api的溝通藉由cookie，而變成stateful。
            HttpClientHandler ret = new HttpClientHandler();
            ret.CookieContainer = new System.Net.CookieContainer();
            ret.ClientCertificateOptions = ClientCertificateOption.Automatic;
            return ret;
        });
        protected static HttpClientHandler _httpClientHandler { get { return _lazy.Value; } }

        protected static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        protected HttpClient _http = null;

        private const string WCT_TOKEN_NAME = "X-Auth-Token";
        public const string WCT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.fff";

        static BaseService()
        {
            // HTTPS的Certification的問題。
            ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };
        }

        public BaseService(string host)
        {
            Debug.Assert(string.IsNullOrEmpty(host) == false, "host cannot be null.");
            if (string.IsNullOrEmpty(host))
            {
                throw new ArgumentNullException("host");
            }

            // check final char
            char lastCh = host.Last();
            if (lastCh.Equals('/') == false && lastCh.Equals('\\') == false)
            {
                host += "/";
            }

            // 用JSON的格式，和Server溝通
            _http = new HttpClient(_httpClientHandler);
            _http.BaseAddress = new Uri(host);
            _http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

        protected TOutput Post<TOutput>(string requestUrl) {
            return Post<string, TOutput>(requestUrl, null);
        }

        protected TOutput Post<TInput, TOutput>(string requestUrl, TInput input)
        {
            Uri path = new Uri(_http.BaseAddress, requestUrl);
            HttpResponseMessage response = _http.PostAsJsonAsync<TInput>(requestUrl, input).Result;
            if (response.IsSuccessStatusCode)
            {
                return response.Content.ReadAsAsync<TOutput>().Result;
            }

            log.Debug("Http Failed, HttpStatus: " + response.StatusCode.ToString() + "\r\nContent: " + response.Content.ReadAsStringAsync().Result);
            return default(TOutput);
        }

        protected TOutput Post<TOutput>(string requestUrl, string token)
        {
            return Post<string, TOutput>(requestUrl, token, null);
        }

        protected TOutput Post<TInput, TOutput>(string requestUrl, string token, TInput input)
        {
            var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
            // Setup header(s)
            request.Headers.Add("Accept", "application/json");
            request.Headers.Add(WCT_TOKEN_NAME, token);
            // Add body content
            request.Content = new StringContent(
                JsonConvert.SerializeObject(input),
                Encoding.UTF8,
                "application/json"
            );
            
            // Send the request
            HttpResponseMessage response = _http.SendAsync(request).Result;
            if (response.IsSuccessStatusCode)
            {
                TOutput result = response.Content.ReadAsAsync<TOutput>().Result;
                return result;
            }

            log.Debug("Http Failed, HttpStatus: " + response.StatusCode.ToString() + "\r\nContent: " + response.Content.ReadAsStringAsync().Result);
            return default(TOutput);
        }

        protected TOutput Get<TOutput>(string reqeustUrl, string token)
        {
            var requestMessage = new HttpRequestMessage(HttpMethod.Get, reqeustUrl);
            requestMessage.Headers.Add("Accept", "application/json");
            requestMessage.Headers.Add(WCT_TOKEN_NAME, token);
            HttpResponseMessage response = _http.SendAsync(requestMessage).Result;
            if (response.IsSuccessStatusCode)
            {
                return response.Content.ReadAsAsync<TOutput>().Result;
            }

            log.Debug("Http Failed, HttpStatus: " + response.StatusCode.ToString() + "\r\nContent: " + response.Content.ReadAsStringAsync().Result);
            return default(TOutput);
        }

        protected TOutput Get<TOutput>(string reqeustUrl)
        {
            Uri path = new Uri(_http.BaseAddress, reqeustUrl);

            HttpResponseMessage response = _http.GetAsync(path).Result;
            if (response.IsSuccessStatusCode)
            {
                return response.Content.ReadAsAsync<TOutput>().Result;
            }

            log.Debug("Http Failed, HttpStatus: " + response.StatusCode.ToString() + "\r\nContent: " + response.Content.ReadAsStringAsync().Result);
            return default(TOutput);
        }

        protected HttpResponseMessage GetHttpResponse(string requestUrl)
        {
            Uri path = new Uri(_http.BaseAddress, requestUrl);
            return _http.GetAsync(path).Result;
        }
    }
}
