using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using XYY.Common.Standard.String;
using XYY.Core.Standard.ExtendMethods;
using XYY.Data.Standard.Order;
using XYY.Model.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.Base;
using XYY.Service.Standard.ChannelApi.Winit.ISPApi;

namespace XYY.Service.Standard.ChannelApi.Winit.LMAApi
{
    public partial class LMAApi : IBaseApi
    {
        public Task<string> GetTrackingNumber(string SystemNo, string TrackingNumber, string ServiceOrderNo, Logistics_Channel channel)
        {
            throw new NotImplementedException();
        }

        public async void CannelOrders(List<String> systemNO)
        {
            var list = await _orderRepository.QueryBySqlAsync("select ServiceOrderNumber4 from Order_Order where SystemNo in @SystemNo", new { SystemNo = systemNO });
            if (list.Count() > 1000)
                throw new Exception("单此仅可取消1000单");
            else
            {
                List<string> cannelOrders = list.Select(x => x.ServicesOrderNo).ToList();
                var response = await Send<dynamic, dynamic>("lma.shipment.cancel", new { winitOrderNOs = cannelOrders });
                string message = response.data.errorMsg;
                throw new Exception(message);
            }
        }

        public async Task<List<BagDeclareErrosResult>> BagDeclare(BagDeclareRequest bagDeclareRequest)
        {
            string updateAction = "lma.shipment.updateWeight";
            List<BagDeclareErrosResult> bagDeclareErrosResults = new List<BagDeclareErrosResult>();
            var list = new List<BagDeclareErrosResult>();
            int j = 0;
            var weightList = new List<BoxDetailItem>();
            weightList = bagDeclareRequest.BatchDeclare.SelectMany(x => x.Value).ToList();
            foreach (var item in bagDeclareRequest.BatchDeclare.Values)
            {
                foreach (var i in item)
                {
                    if (i.ChannelId == 445 || i.ChannelId == 444 || i.ChannelId == 446)
                    {
                        //weightList.Add(i);
                    }
                    else
                    {
                        var cw = await Send<UpdateWeightResult, UpdateWeightModel>(updateAction, new UpdateWeightModel
                        {
                            orderNo = i.ServiceNo,
                            weight = (i.OPWeight / 1000.0m).ToString(),
                            length = "1",
                            height = "1",
                            widht = "1"
                        }, versionValu: "1.0");
                        if (cw.code == "0")
                        {
                            weightList.Add(i);
                        }
                        else
                        {
                            list.Add(new BagDeclareErrosResult { TrackingNumber = i.TrackingNumber, ErrorMessage = cw.msg });
                        }
                    }
                }
            }

            var wg = weightList.GroupBy(x => x.LadingBillNumber);

            foreach (var w in wg)
            {
                for (var i = 0; i < Math.Ceiling((w.Count() / 50.0)); i++)
                {
                    var wlist = w.Skip(i * 50).Take(50);
                    var cl = await Send<ConfirmResult, SendpreadviceRequest>("lma.manifest.sendpreadvice",
               new SendpreadviceRequest
               {
                   sellerManifestNo = w.Key,
                   winitOrderNOs = wlist.Select(x => x.ServiceNo).ToArray()
               }, versionValu: "1.0", keyUp: false);

                    if (cl.msg == "操作成功")
                    {
                        if (cl.data.errorMsgs == null)
                        {

                        }
                        else
                        {
                            list.AddRange(cl.data.errorMsgs.Where(x => !string.IsNullOrEmpty(x.errorMsg)).Select(x =>
                            {
                                string trackingNumber = weightList.FirstOrDefault(y => y.ServiceNo == x.orderNo)?.TrackingNumber;
                                var bg = new BagDeclareErrosResult
                                {
                                    ErrorMessage = x.errorMsg,
                                    TrackingNumber = trackingNumber
                                };
                                return bg;
                            }));
                        }
                    }
                    else
                    {
                        list.AddRange(weightList.Select(x => new BagDeclareErrosResult { TrackingNumber = x.TrackingNumber, ErrorMessage = cl.msg }));
                    }
                }

            }

            return list;
        }
        public string ServiceName => "WinitLMA";

        IOrderRepository _orderRepository;
        public LMAApi(IOrderRepository orderRepository)
        {
            _orderRepository = orderRepository;
        }

        public string GetSign(string token, string actionValue, string app_keyValue, string dataValue,
          string formatValue, string platformValue, string sign_methodValue, string timestampValue,
          string versionValue)
        {
            string str = token + "action" + actionValue + "app_key" + app_keyValue + "data" + dataValue
                + "format" + formatValue + "platform" + platformValue + "sign_method"
                + sign_methodValue + "timestamp" + timestampValue
                + "version" + versionValue + token;
            Console.WriteLine(str);
            return Encryption.Md532(str);
        }

        public string GetJson(object o)
        {
            JsonSerializerSettings setting = new JsonSerializerSettings();
            setting.NullValueHandling = NullValueHandling.Ignore;//null值不序列化
            string strPostData = JsonConvert.SerializeObject(o, Formatting.None, setting);
            JObject jObject = JObject.Parse(strPostData);
            SortedDictionary<string, object> target = KeySort(jObject);
            strPostData = JsonConvert.SerializeObject(target);
            return strPostData;
        }

        /// <summary>
        /// 按ascii顺序排序json对象的顺序
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static SortedDictionary<string, object> KeySort(JObject obj)
        {
            var res = new SortedDictionary<string, object>();
            foreach (var x in obj)
            {
                if (x.Value is JValue) res.Add(x.Key, x.Value);
                else if (x.Value is JObject) res.Add(x.Key, KeySort((JObject)x.Value));
                else if (x.Value is JArray)
                {
                    var tmp = new SortedDictionary<string, object>[x.Value.Count()];
                    for (var i = 0; i < x.Value.Count(); i++)
                    {
                        tmp[i] = KeySort((JObject)x.Value[i]);
                    }
                    res.Add(x.Key, tmp);
                }
            }
            return res;
        }




        public async Task<Result<T>> Send<T, T2>(
            string actionValue,
            T2 dataValue,
           string client_secret = "ZGJJYJA0YZYTYZDJZS00YWZJLTGZZWUTNJLJOTHKZTGXNDK2NTCZODM3NTCWMJC2MDA3MDM=",
           string clintId = "MWRMNGZKODYTYZHMNI00NZG0LWJKZWYTMMYZY2IZYZRIZDK1",
           string formatValue = "json",
           string platformValue = "xyy",
           string sign_methodValue = "md5",
           string versionValu = "3.0",
            string app_keyValue = "alice-xie@xingyunyi.cn",
            string token = "28BBD9FABE5696E814F06218E5C200CC",
             string url = "https://openapi.winit.com.cn/openapi/service",
             bool keyUp = true
           )
        {
            string timestampValue = DateTime.Now.ToString_yyyyMMddHHmmss();
            string strData = keyUp ? GetJson(dataValue) : Newtonsoft.Json.JsonConvert.SerializeObject(dataValue);

            string sign = GetSign(token, actionValue, app_keyValue
                , strData, formatValue, platformValue, sign_methodValue, timestampValue, versionValu).ToUpper();
            string client_sign = GetClient_Sign(client_secret, actionValue, app_keyValue, strData,
                formatValue, platformValue, sign_methodValue, timestampValue, versionValu).ToUpper();
            RequestOrder<T2> request = new RequestOrder<T2>
            {
                action = actionValue,
                data = dataValue,
                client_id = clintId,
                app_key = app_keyValue,
                format = formatValue,
                timestamp = timestampValue,
                language = "zh_CN",
                platform = platformValue,
                sign_method = sign_methodValue,
                version = versionValu,
                sign = sign,
                client_sign = client_sign
            };
            RestSharp.RestClient rest = new RestSharp.RestClient(url);
            RestSharp.RestRequest restRequest = new RestSharp.RestRequest(RestSharp.Method.POST);
            restRequest.AddJsonBody(request);
            var response = await rest.ExecuteTaskAsync(restRequest);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                return Newtonsoft.Json.JsonConvert.DeserializeObject<Result<T>>(response.Content);
            }
            else
            {
                throw new Exception(response.ErrorMessage ?? response.Content);
            }
        }

        public string GetClient_Sign(string client_secret, string actionValue, string app_keyValue, string dataValue,
            string formatValue, string platformValue, string sign_methodValue, string timestampValue, string versionValue
            )
        {
            string str2 = client_secret + "action" + actionValue + "app_key" + app_keyValue + "data" + dataValue
                + "format" + formatValue + "platform" + platformValue + "sign_method" + sign_methodValue
                + "timestamp" + timestampValue + "version" + versionValue + client_secret;
            return Encryption.Md532(str2);
        }
        //public string[] ToArray(string str, int maxLength)
        //{
        //    string[] arr = str.Split(' ', '.');
        //    int page = ((str.Length + maxLength) - 1) / maxLength;
        //    string[] addressArr = new string[page];

        //    int flag = 0;
        //    int t = arr.Count();
        //    for (int i = 0; i < page; i++)
        //    {
        //        string temp = "";
        //        for (int j = 0; j < t; j++)
        //        {
        //            if ((temp += arr[flag] + " ").Length <= maxLength)
        //            {
        //                addressArr[i] += arr[flag] + " ";
        //                flag++;
        //            }
        //        }
        //        t = arr.Count() - flag;
        //    }
        //    return addressArr;
        //}

        public OrderInfo ConvertOrder(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel)
        {
            string refNo = order.SystemNo;
            if (order.CustomerId == 796)
            {
                refNo = order.CustomerOrderNo;
            }
            string productCode = channel.ServiceChannelCode.Split(';')[0];
            string pickupAddressCode = channel.ServiceChannelCode.Split(';')[1];
            string[] receiveryAddress = order.ReceiverStreet.Replace("|", "").ToArray(32);
            if (receiveryAddress.Length > 2)
                throw new Exception("地址超长");
            var postOrder = new OrderInfo
            {
                sellerOrderNo = refNo,
                productInfo = new ProductInfo { winitProductCode = productCode },
                shipper = new Shipper { pickupAddressCode = pickupAddressCode },
                receiver = new Receiver
                {
                    state = order.ReceiverState,
                    city = order.ReceiverCity,
                    receiverName = order.ReceiverName,
                    phoneNo = order.ReceiverPhone,
                    addressLine1 = receiveryAddress[0],
                    addressLine2 = receiveryAddress.Length == 2 ? receiveryAddress[1] : "",
                    countryCode = order.ReceiverCountryCode,
                    postCode = order.ReceiverZipCode
                },
                totalParcelsNumber = "1",
                totalParcelsWeight = (Math.Floor(order.CustomerWeight / 10.0) / 100).ToString("0.00"),
                parcelList = new List<ParcelListItem>
                {
                    new ParcelListItem
                    {
                        height="1",
                        width="1",
                        length="1",
                        weight=(order.CustomerWeight / 1000.0).ToString("0.000"),
                    merchandiseList = new List<MerchandiseListItem>{ }
                    }
                }
            };
            postOrder.parcelList[0].merchandiseList = goods.Select(x => new MerchandiseListItem
            {
                merchandiseCode = x.HsCode,
                declaredCurrency = x.DeclareCurrency,
                declaredNameCn = x.CnName,
                declaredNameEn = x.EnName,
                declaredValue = Math.Round(x.DeclareFee, 2).ToString("0.00"),
                quantity = x.Quantity.ToString()
            }).ToList();
            if (channel.PublicCode == "W-DE-DHL-LMA")
            {
                string house = "";
                string street = "";
                if (string.IsNullOrWhiteSpace(order.House))
                {


                    string receiverStreet = order.ReceiverStreet.Trim();
                    string pattern = "^\\d+|\\d+$";
                    var regex = new Regex(pattern);
                    var match = regex.Match(receiverStreet);
                    if (match.Success)
                    {
                        var val = match.Value;
                        street = receiverStreet.Replace(val, string.Empty);
                        house = val;
                    receiveryAddress = street.Replace("|", "").ToArray(32);
                    }
                    else
                    {
                        throw new Exception("德国地址需要包含街道与门牌号");
                    }
                }
                else
                {
                    house = order.House;

                    street = order.ReceiverStreet.Trim();
                    street = TrimEnd(TrimEnd(street, house).Trim(), house);
                    receiveryAddress = street.Replace("|", "").ToArray(32);
                    //去掉门牌号重复的问题;
                }
                postOrder.receiver.houseNo = house;
                postOrder.receiver.addressLine1 = receiveryAddress[0];
                postOrder.receiver.addressLine2 = receiveryAddress.Length == 2 ? receiveryAddress[1] : "";
            }

            return postOrder;
        }

        public string TrimEnd(string strSrc, string strTrim)
        {
            if (strTrim == " " || string.IsNullOrEmpty(strTrim))
            {
                return strSrc;
            }
            if (strSrc.EndsWith(strTrim))
            {
                string strDes = strSrc.Substring(0, strSrc.Length - strTrim.Length);
                return TrimEnd(strDes, strTrim);
            }
            return strSrc;
        }

        public async Task<UploadResult> DataUpload(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel, ExtendArg arg)
        {
            string refNo = order.SystemNo;
            if (order.CustomerId == 796)
            {
                refNo = order.CustomerOrderNo;
            }
            Result<OrderResult> r = null;
            var winitOrder = await _orderRepository.GetWinitOrderNo(refNo);
            if (!string.IsNullOrEmpty(winitOrder))
            {
                r = new Result<OrderResult>
                {
                    msg = "操作成功",
                    data = new OrderResult
                    {
                        orderNo = winitOrder
                    }
                };
            }
            else
            {
                string action = "lma.shipment.create";
                string ver = "3.0";
                if (channel.PublicName.StartsWith("W-FC") ||
                    channel.PublicName.StartsWith("W-PM")
                    || channel.PublicName.EndsWith("LMA")
                    || channel.PublicName.EndsWith("LMA-Y"))
                {
                    action = "lma.shipment.createOrderSync";
                    ver = "1.0";
                }
                var o = ConvertOrder(order, goods, channel);
                if (order.CustomerId == 876)
                {
                    if (o.shipper.pickupAddressCode == "XYYUS900")
                    {
                        o.shipper.pickupAddressCode = "XYY_USPS_90045_91748";
                    }
                    else if (o.shipper.pickupAddressCode == "XYYUS601")
                    {
                        o.shipper.pickupAddressCode = "XYY_USPS_60007_91748";
                    }
                    else if (o.shipper.pickupAddressCode == "XYYUS114")
                    {
                        o.shipper.pickupAddressCode = "XYY_USPS_11434_91748";
                    }
                }
                r = await Send<OrderResult, OrderInfo>(
                   action, o, versionValu: ver);
                if (r.msg == "操作成功")
                    await _orderRepository.AddWinitLog(r.data.orderNo, refNo);
            }
            if (r.msg == "操作成功")
            {
                var r2 = await Send<LabelResultInfo, LabelRequest>("lma.shipment.print", new LabelRequest
                {
                    winitOrderNo = r.data.orderNo
                });
                winitOrder = r.data.orderNo;
                if (r2.msg == "操作成功")
                {
                    return new UploadResult
                    {
                        DownloadUrl = r2.data.labelList[0].label,
                        IsSuccess = true,
                        TrackingNumber = r2.data.labelList[0].trackingNo,
                        ServiceOrderNumber = winitOrder
                    };
                }
                else
                {
                    throw new Exception(r2.msg);
                }
            }
            else
            {
                throw new Exception(r.msg);
            }
        }


        public class LabelResultInfo
        {
            public LabelResultItem[] labelList
            {
                get; set;
            }
        }

        public class LabelResultItem
        {
            public string trackingNo
            {
                get; set;
            }

            public string label
            {
                get; set;
            }
        }

        public class LabelRequest
        {
            public string winitOrderNo
            {
                get; set;
            }
        }

        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            string base64 = result.DownloadUrl;
            var bytes = Convert.FromBase64String(base64);
            return bytes;
        }

        public async Task<List<string>> Confims(List<OrderConfimRequest> order, Logistics_Channel channel)
        {

            //重量更新
            string updateAction = "lma.shipment.updateWeight";
            foreach (var item in order)
            {
                var cw = await Send<UpdateWeightResult, UpdateWeightModel>(updateAction, new UpdateWeightModel
                {
                    orderNo = item.OrderNo,
                    weight = (item.OPWeight / 1000.0m).ToString(),
                    length = "1",
                    height = "1",
                    widht = "1"
                }, versionValu: "1.0");
                if (cw.code == "0")
                {

                }
                else
                {
                    throw new Exception(cw.msg);
                }
            }
            return new List<string>();


            //var cl = await Send<ConfirmResult, ConfirmInfo>("lma.shipment.confirm",
            //      new ConfirmInfo { winitOrderNOs = order.Select(x => x.OrderNo).ToList() }, versionValu: "1.0", keyUp: false);
            //if (cl.msg == "操作成功")
            //{
            //    if (cl.data.failedCount == 0)
            //    {
            //        return new List<string>();
            //    }
            //    else
            //    {
            //        return cl.data.errorMsgs.Where(x => !string.IsNullOrEmpty(x.errorMsg)).Select(x => x.orderNo)
            //            .ToList();
            //    }
            //}
            //else
            //{
            //    throw new Exception("确认失败:" + cl.msg);
            //}
        }
        public void CannelOrdersByModel(logistics_ChannelCancel logistics_ChannelCancel)
        {
            List<string> cannelOrderSystemNos = new List<string>() { logistics_ChannelCancel.SystemNo };
            var list =
                _orderRepository.QueryBySqlAsync("select * from Order_Order where SystemNo in @SystemNo", new { SystemNo = cannelOrderSystemNos }).Result.FirstOrDefault();
            if (list != null)
            {
                var response = Send<SendpreadviceRequest, dynamic>("lma.shipment.cancel",
                    new SendpreadviceRequest { winitOrderNOs = new string[] { list.ServicesOrderNo } }, keyUp: false, versionValu: "1.0").Result;
                string message = response.msg;
                logistics_ChannelCancel.ResultState = ResultStateEnum.成功.GetValue();
            }
        }
    }
}
