using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using XYY.Model.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.Base;
using Newtonsoft.Json;
using XYY.Common.Standard.String;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.IO;
using System.Threading;
using System.Net.Http.Headers;
using System.Net.Security;
using RestSharp;
using Microsoft.Extensions.Logging;
using XYY.Data.Standard.Order;

namespace XYY.Service.Standard.ChannelApi.YunYITong
{

    public class Api : IBaseApi
    {
        public Task<string> GetTrackingNumber(string SystemNo, string TrackingNumber, string ServiceOrderNo, Logistics_Channel channel)
        {
            throw new NotImplementedException();
        }
        ILogger<Api> _logger;
        IOrder_OrderPrintQtyRepository _orderPrintQtyRepository;
        public Api(ILogger<Api> logger, IOrder_OrderPrintQtyRepository orderPrintQtyRepository)
        {
            _orderPrintQtyRepository = orderPrintQtyRepository;
            _logger = logger;
        }
        public string ServiceName => "YunYITong";

        public async Task<UploadResult> DataUpload(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel, ExtendArg arg)
        {
            DateTime dateTime = DateTime.Now;
            var post = ConvertOrder(order, goods, channel);
            ApiResult<OrderResult> result = null;
            try
            {
                result = await SendData<OrderResult>(channel, "CB.REMOTE.ADDORDER", post);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("该订单号已存在"))
                {
                    order.SystemNo = order.SystemNo + _orderPrintQtyRepository.GetPackagePrintQty(order.TransferNumber);
                    post = ConvertOrder(order, goods, channel);
                    result = await SendData<OrderResult>(channel, "CB.REMOTE.ADDORDER", post);
                }
                else
                {
                    _logger.LogWarning(ServiceName + " - " + channel.Id + "下单错误:请求对方参数{@Request}，错误信息" + ex.Message, post);
                    throw new Exception(ex.Message);
                }
            }
            int qty = 0;
            if (!string.IsNullOrEmpty(result.data.cbOrderNo))
            {
                ApiResult<OrderQueryResultData> queryRseult = new ApiResult<OrderQueryResultData>
                {
                    data = new OrderQueryResultData
                    {
                        list = new List<OrderQueryResultItem>()
                       {
                            new OrderQueryResultItem
                            {
                                url = string.Empty
                            }
                        }
                    }
                };
                do
                {
                    if (qty++ > 6)
                        throw new Exception("查询面单链接失败");
                    System.Threading.Thread.Sleep(8000);
                    queryRseult = await SendData<OrderQueryResultData>(channel, "CB.REMOTE.QUERYORDER",
                 new OrderQueryRequest
                 {
                     cbOrderNo = result.data.cbOrderNo,
                     referBillNo = result.data.referBillNo,
                     startTime = dateTime.ToString_yyyyMMddHHmmss(),
                     endTime = DateTime.Now.AddDays(1).ToString_yyyyMMddHHmmss(),
                     pageNum = 1,
                     pageSize = 10,
                     linkId = channel.ServiceChannelCode
                 });
                    if (queryRseult.data.list == null || queryRseult.data.list.Count == 0)
                        throw new OrderApiException("api调用失败:未找到运单信息", result.data.cbOrderNo, channel.Id, OrderApiMethod.查单);
                    if (!string.IsNullOrEmpty(queryRseult.data.list[0].abnormalDesc))
                    {
                        throw new Exception("下单失败" + queryRseult.data.list[0].abnormalDesc);
                    }

                } while (string.IsNullOrEmpty(queryRseult.data.list[0].expressWbNo));

                var item = queryRseult.data.list[0];
                item.url = $"http://files.esinotrans.cn/waybill/{item.expressWbNo}.pdf";
                _logger.LogWarning(ServiceName + " - " + channel.Id + "下单完成:请求对方参数{@Request}", post);
                return new UploadResult
                {
                    DownloadUrl = item.url,
                    ServiceOrderNumber = item.referBillNo,
                    ServiceOrderNumber2 = item.cbOrderNo,
                    TrackingNumber = item.expressWbNo,
                    IsSuccess = true,
                    destinationCode = item.destinationCode
                };
            }
            else
            {
                throw new OrderApiException("api调用失败:小包单号为空", order.SystemNo, channel.Id, OrderApiMethod.下单);
            }
        }

        private Order ConvertOrder(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel)
        {
            if (order.ReceiverCountryCode == "US")
            {
                if (!string.IsNullOrEmpty(order.House))
                {
                    order.ReceiverStreet = order.ReceiverStreet + order.House;
                }

                if (!string.IsNullOrWhiteSpace(order.ReceiverState))
                {
                    order.ReceiverState = order.ReceiverState.Trim();
                }

                if (string.IsNullOrEmpty(order.ReceiverPhone))
                {
                    order.ReceiverPhone = "1";
                }

                if (!string.IsNullOrWhiteSpace(order.ReceiverCity))
                {
                    order.ReceiverCity = order.ReceiverCity.Trim();
                }

                string[] Remote = new string[] { "AK", "HI", "GU", "AS", "MP", "PR", "VI", "AE", "AP" };
                order.CustomerOrderNo = order.CustomerOrderNo.Replace("_", "");
                Dictionary<string, string> pairs = new Dictionary<string, string>
                {
                    { "Washington", "WA" },
                    { "Oregon", "OR" },
                    { "California", "CA" },
                    { "Nevada", "NV" },
                    { "Idaho", "ID" },
                    { "Utah", "UT" },
                    { "Arizona", "AZ" },
                    { "Montana", "MT" },
                    { "Wyoming", "WY" },
                    { "Colorado", "CO" },
                    { "New Mexico", "NM" },
                    { "Wisconsin", "WI" },
                    { "Illinois", "IL" },
                    { "Tennessee", "TN" },
                    { "Mississippi", "MS" },
                    { "Michigan", "MI" },
                    { "Indiana", "IN" },
                    { "Kentucky", "KY" },
                    { "Alabama", "AL" },
                    { "Ohio", "OH" },
                    { "West Virginia", "WV" },
                    { "Virginia", "VA" },
                    { "North Carolina", "NC" },
                    { "South Carolina", "SC" },
                    { "Georgia", "GA" },
                    { "North Dakota", "ND" },
                    { "South Dakota", "SD" },
                    { "Nebraska", "NE" },
                    { "Kansas", "KS" },
                    { "Oklahoma", "OK" },
                    { "Texas", "TX" },
                    { "Minnesota", "MN" },
                    { "Iowa", "IA" },
                    { "Missouri", "MO" },
                    { "Arkansas", "AR" },
                    { "Louisiana", "LA" },
                    { "Florida", "FL" },
                    { "Pennsylvania", "PA" },
                    { "New York", "NY" },
                    { "Washington D. C.", "DC" },
                    { "Maryland", "MD" },
                    { "Delaware", "DE" },
                    { "New Jersey", "NJ" },
                    { "Connecticut", "CT" },
                    { "Rhode Island", "RI" },
                    { "Massachusetts", "MA" },
                    { "Maine", "ME" },
                    { "New Hampshire", "NH" },
                    { "Vermont", "VT" },
                    {"Alaska","AK" },
                    {"Hawaii","HI" }
                };

                if (!pairs.Keys.Any(x => x.Equals(order.ReceiverState, StringComparison.CurrentCultureIgnoreCase))
                    && !pairs.Values.Any(x => x.Equals(order.ReceiverState, StringComparison.CurrentCultureIgnoreCase))
                    )
                {
                    if (pairs.Keys.Any(x => x.Equals(order.ReceiverCity, StringComparison.CurrentCultureIgnoreCase)))
                    {
                        string state = order.ReceiverState;
                        order.ReceiverState = pairs.Where(x => x.Key.Equals(order.ReceiverCity, StringComparison.CurrentCultureIgnoreCase)).First().Value;
                        order.ReceiverCity = state;
                    }
                    else if (pairs.Values.Any(x => x.Equals(order.ReceiverCity, StringComparison.CurrentCultureIgnoreCase)))
                    {
                        string state = order.ReceiverState;
                        order.ReceiverState = order.ReceiverCity;
                        order.ReceiverCity = order.ReceiverState;
                    }
                    else
                    {
                        throw new Exception("美国专线必须传入标准的州名或州简写");
                    }
                }
                else
                    if (pairs.Keys.Any(x => x.Equals(order.ReceiverState, StringComparison.CurrentCultureIgnoreCase)))
                {
                    order.ReceiverState = pairs.Where(x => x.Key.Equals(order.ReceiverState, StringComparison.CurrentCultureIgnoreCase)).First().Value;
                }
                if (Remote.Any(x => x.Equals(order.ReceiverState, StringComparison.CurrentCultureIgnoreCase)))
                {
                    throw new Exception("美国该地区不支持派送");
                }
            }

            foreach (var item in goods)
            {
                //四舍五入到美分
                item.DeclareFee = Math.Round(item.DeclareFee, 2);
            }

            if (goods.Any(x => x.Weight == 0))
            {
                goods.ForEach(x => x.Weight = (int)Math.Round((order.CustomerWeight) / (decimal)goods.Sum(x => x.Quantity)));
            }

            Order post = new Order
            {
                linkId = channel.ServiceChannelCode,
                referBillNo = order.SystemNo,
                orderTotalAmount = goods.Sum(x => x.DeclareFee * x.Quantity).ToString("0.00"),
                orderGoodsAmount = goods.Sum(x => x.DeclareFee * x.Quantity).ToString("0.00"),
                orderTotalCount = goods.Sum(x => x.Quantity),
                orderTime = DateTime.Now.ToString_yyyyMMddHHmmss(),
                roughWeight = order.CustomerWeight,
                cnDesc = string.Join(",", goods.Select(x => x.CnName).ToArray()),
                enDesc = string.Join(",", goods.Select(x => x.EnName).ToArray()),
                isEmbargo = 0,
                isCharged = 0,
                orderCurrency = "502",
                consignee = new Consignee
                {
                    city = order.ReceiverCity,
                    consigneeName = order.ReceiverName,
                    consigneeMobile = order.ReceiverPhone,
                    province = order.ReceiverState,
                    consigneeAddress = order.ReceiverStreet,
                    consigneeCountry = order.ReceiverCountryCode,
                    consigneePost = order.ReceiverZipCode
                },
                orderDetailList = goods.Select(x => new OrderDetail
                {
                    goodsCustomsCode = x.HsCode,
                    goodsNetWeight = x.Weight,
                    unitPrice = x.DeclareFee.ToString("0.00"),
                    goodCurrency = "502",
                    model = x.CnName,
                    itemCode = x.GoodsNumber,
                    itemCount = x.Quantity,
                    itemEnglishName = x.EnName,
                    itemName = x.CnName
                }).ToList()
            };
            return post;
        }


        private async Task<ApiResult<T>> SendData<T>(Logistics_Channel channel, string method, object data)
        {
            OrderApiMethod errorMethod = method == "CB.REMOTE.ADDORDER" ? OrderApiMethod.下单 : OrderApiMethod.查单;
            string url = channel.ApiHost;
            if (errorMethod == OrderApiMethod.查单)
            {
                url = channel.LabelUrl;
            }
            string apiId = channel.ApiKey;
            string apiSecretkey = channel.ApiSecret;
            string version = "1.0";
            string format = "json";
            string timestamp = DateTime.Now.ToString_yyyyMMddHHmmss();
            string strData = JsonConvert.SerializeObject(data);
            string sign = Encryption.Md532(apiSecretkey + apiId + strData + format + method + timestamp + version + apiSecretkey);

            var postData = new
            {
                appid = apiId,
                method = method,
                format = format,
                data = strData,
                version = version,
                timestamp = timestamp,
                sign = sign
            };
            string postDataStr = Newtonsoft.Json.JsonConvert.SerializeObject(postData);

            //      var h = new SocketsHttpHandler();
            //      h.ResponseHeaderEncodingSelector = (header, content) =>
            //      {
            //          return UTF8Encoding.UTF8;
            //      };
            //      var client = HttpClientFactory.Create(h);
            //      h.Proxy = new WebProxy("localhost:8888");
            //      client.BaseAddress = new Uri(channel.ApiHost);
            //      var request = new HttpRequestMessage(HttpMethod.Post, "") { Content = new StringContent(postDataStr, Encoding.UTF8, "application/json") };
            //      client.DefaultRequestHeaders
            //.Accept
            //.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            //      try
            //      {
            //          var r = await client.SendAsync(request);
            //          Console.WriteLine(r.StatusCode);
            //          Console.WriteLine(r.Content);
            //      }
            //      catch (HttpRequestException ex)
            //      {

            //      }

            //      return null;
            var client = new RestClient(url);
            //client.Proxy = new WebProxy("localhost:8888");
            client.FailOnDeserializationError = true;
            var requeslt = new RestRequest(Method.POST);
            requeslt.AddJsonBody(postData);
            var webResponse = await client.ExecutePostAsync(requeslt);
            if (webResponse.StatusCode == HttpStatusCode.OK)
            {
                ApiResult<T> result = null;
                try

                {
                    result = JsonConvert.DeserializeObject<ApiResult<T>>(webResponse.Content);
                }
                catch (Exception ex)
                {
                    throw new OrderApiException("api解析失败" + webResponse.Content, postDataStr, channel.Id, errorMethod);
                }
                if (result.status != "200")
                {

                    throw new OrderApiException("api调用失败" + result.message, postDataStr, channel.Id, errorMethod);

                }
                else
                {
                    return result;
                }

            }
            else
            {
                throw new OrderApiException("api请求失败:" + webResponse.ErrorMessage ?? webResponse.Content, webResponse.ErrorMessage ?? webResponse.Content, channel.Id, errorMethod);
            }

        }

        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            if (string.IsNullOrEmpty(result.DownloadUrl))
            {
                throw new OrderApiException("api下载面单失败:面单路径为空", result.ServiceOrderNumber2, channel.Id, OrderApiMethod.下载面单);
            }
            else
            {
                System.Net.WebClient client = new System.Net.WebClient();
                //client.Proxy = new WebProxy("127.0.0.1:8888");
                try
                {
                    byte[] data = null;
                    for (int i = 0; i < 3; i++)
                    {
                        try
                        {
                            data = await client.DownloadDataTaskAsync(result.DownloadUrl);
                            break;
                        }
                        catch
                        {
                            System.Threading.Thread.Sleep(3000);
                        }

                    }
                    if (data == null)
                        throw new OrderApiException("下载面单失败:", result.DownloadUrl, channel.Id, OrderApiMethod.下载面单);
                    string destPort = order.DestinationPortCode;
                    return data;

                }
                catch (Exception ex)
                {
                    throw new OrderApiException("api下载面单失败:" + ex.Message, result.DownloadUrl, channel.Id, OrderApiMethod.下载面单);
                }
            }
        }
         
        public Task<List<string>> Confims(List<OrderConfimRequest> order, Logistics_Channel channel)
        {
            throw new NotImplementedException();
        }

        public Task<List<BagDeclareErrosResult>> BagDeclare(BagDeclareRequest bagDeclareRequest)
        {
            throw new NotImplementedException();
        }

        public void CannelOrders(List<string> systemNO)
        {
            throw new NotImplementedException();
        }
        public void CannelOrdersByModel(logistics_ChannelCancel logistics_ChannelCancel)
        {
            throw new NotImplementedException();
        }

        public class ApiResult<T>
        {
            public string status
            {
                get; set;
            }

            public string message
            {
                get; set;
            }

            public string code
            {
                get; set;
            }

            public T data
            {
                get; set;
            }
        }
    }
}
