using NPOI.SS.Formula.PTG;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using XYY.Common.Standard;
using XYY.Model.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.AddressHelper;
using XYY.Service.Standard.ChannelApi.Base;
using XYY.Service.Standard.ChannelApi.MIQ;

namespace XYY.Service.Standard.ChannelApi.IMG
{
    public class Api : IBaseApi
    {
        public string ServiceName => "IMG-USPS";

        public async Task<List<BagDeclareErrosResult>> BagDeclare(BagDeclareRequest bagDeclareRequest)
        {
            if (bagDeclareRequest?.BatchDeclare?.Values == null)
                return new List<BagDeclareErrosResult>();
            var r = new List<BagDeclareErrosResult>();
            var items = bagDeclareRequest.BatchDeclare.SelectMany(i => i.Value);
            var pairs = items.Select(i => new { i.TrackingNumber, i.BoxNumber });

            var trackingNumbers = pairs.Select(i => i.TrackingNumber).ToList();
            int pageCount = (int)Math.Ceiling(trackingNumbers.Count / 100.0);
            for (int i = 0; i <= pageCount; i++)
            {
                var tlist = trackingNumbers.Skip(100 * i).Take(100).ToList();
                var errors = await ConfimsList(tlist, bagDeclareRequest.Channel);
                if (errors?.Any() == true)
                {
                    var errorNums = errors
                        .Where(x=>x.message != "运单状态不符，该运单已确定")
                        .Select(i => i.picNumber);
                    var errorPairs = pairs.Where(p => errorNums.Contains(p.TrackingNumber));
                    var r2 = errorPairs.Select(i =>
                    {
                        var err = errors.FirstOrDefault(e => e.picNumber == i.TrackingNumber);
                        return new BagDeclareErrosResult { BoxNumber = i.BoxNumber, TrackingNumber = i.TrackingNumber, ErrorMessage = err?.message };

                    }).ToList();
                    r.AddRange(r2);
                }
                else { 
                } 
            }
            return r;
        }

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

        public void CannelOrdersByModel(logistics_ChannelCancel logistics_ChannelCancel)
        {
            throw new NotImplementedException();
        }

        public async Task<List<string>> Confims(List<OrderConfimRequest> order, Logistics_Channel channel)
        {
            List<string>errors=new List<string> ();
            //分批 50 一条去执行
            int pageCount = (int)Math.Ceiling(order.Count / 50.0);
            for (int i = 0; i <= pageCount; i++)
            {
                List<string> result = order.Skip(50*i).Take(50).Select(i => i.TrackingNumber).ToList();
                var tempErrors = await ConfimsList(result, channel);
                if (tempErrors?.Any() == true)
                {
                    errors.AddRange(tempErrors.Select(i => i.picNumber).ToList());
                }
            }
            return errors;
        }
        public async Task<List<Error>> ConfimsList(List<string> trackingNumbers, Logistics_Channel channel)
        {
            //channel.ApiHost = "http://220.231.152.2:3168/newwl/";
            //channel.ApiKey = "1006106";

            ConfirmOrderRequest confirmOrderRequest = new ConfirmOrderRequest
            {
                picNumbers = new PicNumbers { picNumber = trackingNumbers },
                zrsupplyShipToken = channel.ApiKey,
                appToken = channel.ApiSecret,
            };

            RestClient client = new RestClient(channel.ApiHost);
            RestRequest request = new RestRequest("/confirmOrder.xsv");
            request.Method = Method.POST;

            request.AddJsonBody(confirmOrderRequest);

            var response = await client.ExecuteAsync<ConfirmOrderReponse>(request);

            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                if (response.Data?.refund == null)
                {
                    string errMsg = string.IsNullOrEmpty(response.ErrorMessage) ? response.Content : response.ErrorMessage;
                    var errors = CreateErrorItems(trackingNumbers, errMsg);
                    return errors.ToList();
                }
                else if (response.Data.refund?.refundStatusDetail?.error?.Any() == true)
                {
                    return response.Data.refund.refundStatusDetail.error;
                }
            }
            else
            {
                string errMsg = string.IsNullOrEmpty(response.ErrorMessage) ? response.Content : response.ErrorMessage;
                var errs = CreateErrorItems(trackingNumbers, errMsg);
                return errs.ToList();
            }
            return Enumerable.Empty<Error>().ToList();
        }

        private IEnumerable<Error> CreateErrorItems(List<string> trackingNumbers, string errMsg)
        {
            var errs = trackingNumbers.Select(i => new Error { picNumber = i, message = errMsg });
            return errs;
        }

        public async Task<UploadResult> DataUpload(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel, ExtendArg arg)
        {
            //channel.ApiHost = "http://220.231.152.2:3168/newwl/";
            //channel.ApiKey = "1006106";

            string host = channel.ApiHost;

            new USAddressCheck().CheckUSOrder(order, false);

            //var port = ACIZipZones.GetPort(order.ReceiverZipCode); 
            CheckRecepient(order);
            CreateOrderParameter createOrderParam = GenCreateOrderParam(order, goods, channel);
            //var json = Newtonsoft.Json.JsonConvert.SerializeObject(createOrderParam);
            RestClient client = new RestClient(host);
            RestRequest request = new RestRequest("/tuffyOrder.xsv");
            request.Method = Method.POST;

            request.AddJsonBody(createOrderParam);
            //request.AddHeader("api-key", apiKey);

            var response = await client.ExecuteAsync<CreateOrderResponse>(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var content = response.Content;
                if (string.IsNullOrWhiteSpace(content))
                {
                    throw new Exception("下单api返回内容为空");
                }

                CreateOrderResponse data = response.Data;

                if (data.success == true)
                {
                    if (data.data != null)
                    {
                        var result = data.data;
                        string trackingNumber = result.WaybillNum;
                        string serviceOrderId = result.TailSingleNo;
                        string labelUrl = result.LabelUrlPdf;

                        var uploadResult = new UploadResult
                        {
                            IsSuccess = true,
                            ServiceOrderNumber = serviceOrderId,
                            TrackingNumber = trackingNumber,
                            DownloadUrl = labelUrl
                        };
                        return uploadResult;
                    }
                    else
                    {
                        throw new Exception("下单api返回订单数据为空");
                    }

                }
                else
                {
                    if (content.Contains("LabelUrlPdf"))
                    {
                        if (data.data != null)
                        {
                            var result = data.data;
                            string trackingNumber = result.WaybillNum;
                            string serviceOrderId = result.TailSingleNo;
                            string labelUrl = result.LabelUrlPdf;

                            var uploadResult = new UploadResult
                            {
                                IsSuccess = true,
                                ServiceOrderNumber = serviceOrderId,
                                TrackingNumber = trackingNumber,
                                DownloadUrl = labelUrl
                            };
                            return uploadResult;
                        }
                        else
                        {
                            throw new Exception("下单api返回订单数据为空");
                        }
                    }
                    string msg = content;
                    throw new Exception($"下单出错 {msg}");
                }

            }
            else
            {
                string msg = string.IsNullOrWhiteSpace(response.ErrorMessage) ? response.Content : response.ErrorMessage;
                throw new Exception($"下单出错 {msg}");
            }
        }

        private CreateOrderParameter GenCreateOrderParam(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel)
        {
            string businessType = "logisticChannel";
            string refNo = order.SystemNo;
            string callingTime = DateTime.Now.ToString_yyyyMMddHHmmss();
            string signature = CreateSignature(refNo, businessType, channel.ApiKey, channel.ApiSecret, callingTime);

            CreateOrderParameter orderParameter = new CreateOrderParameter
            {
                zrsupplyShipToken = channel.ApiKey,
                appToken = channel.ApiSecret,
                businessType = businessType,
                callingTime = callingTime,
                verification = signature,
                data = CreateOrderDate(refNo, order, goods, channel)
            };
            return orderParameter;
        }

        private OrderData CreateOrderDate(string refNo, Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel)
        {
            string poZipCode = "";
            if (channel.PublicCode.Contains("ORD", StringComparison.OrdinalIgnoreCase))
                poZipCode = "60007";
            else if (channel.PublicCode.Contains("LAX", StringComparison.OrdinalIgnoreCase))
                poZipCode = "90001";
            else if (channel.PublicCode.Contains("JFK", StringComparison.OrdinalIgnoreCase) 
                && (channel.PublicCode.Contains("FC", StringComparison.OrdinalIgnoreCase)|| 
                channel.PublicCode.Contains("GA", StringComparison.OrdinalIgnoreCase)))
                poZipCode = "11351";
            else if (channel.PublicCode.Contains("JFK", StringComparison.OrdinalIgnoreCase) && channel.PublicCode.Contains("PM", StringComparison.OrdinalIgnoreCase))
                poZipCode = "11413";
            if (poZipCode == "")
                throw new Exception("不能确定poZipCode");

            var addressArr = order.ReceiverStreet.Replace("|", "").ToArray(80);
            string weight = ((order.OPWeight <= 0 ? order.CustomerWeight : order.OPWeight) / 1000m).ToString("F2");

            List<DetailList> detailList = CreateGoodsList(goods);
            string SenderCity = channel.SenderCity;
            string SenderName = channel.SenderName;
            string SenderPhone = channel.SenderPhone;
            string SenderZipCode = channel.SenderZipCode;
            string SenderState = channel.SenderState;
            string SenderStreet = channel.SenderStreet;
            string SenderCompany = null;//channel.SenderCompany;
            if (order.CustomerId == 876)
            {
                SenderCompany = null;
                SenderCity = "Temecula";
                SenderName = "RETURN DEPARTMENT";
                SenderPhone = "";
                SenderZipCode = "92590";
                SenderState = "CA";
                SenderStreet = "42261 Zevo Dr";
            }

            OrderData orderData = new OrderData
            {
                salesOrder = new SalesOrder
                {
                    buyerAddress = addressArr[0],
                    buyerAddress2 = addressArr.Length > 1 ? addressArr[1] : string.Empty,
                    buyerCity = order.ReceiverCity,
                    buyerCode = order.ReceiverZipCode,
                    buyerCompany = order.ReceiverCompany,
                    buyerPhone = order.ReceiverPhone,
                    buyerCountries = order.ReceiverCountryCode,
                    buyerName = order.ReceiverName,
                    buyerProvince = order.ReceiverState,
                    carrierCode = channel.ServiceChannelCode,
                    cusDocumentNo = refNo,
                    fromCity = SenderCity,
                    fromCompany = SenderCompany,
                    fromName = SenderName,
                    fromPhone = SenderPhone,
                    fromPostalCode = SenderZipCode,
                    fromState = SenderState,
                    packageHeight = "1",
                    packageLength = "1",
                    packageWeight = weight,
                    packageWidth = "1",
                    returnAddress1 = SenderStreet,
                    returnAddress2 = string.Empty,
                    needPushManifest = "Y",
                    poZipCode = poZipCode,
                    detailList = detailList

                }
            };
            return orderData;
        }

        private List<DetailList> CreateGoodsList(List<Order_OrderGoods> goods)
        {
            List<DetailList> result = goods.Select(i => new DetailList
            {
                goodsName = i.EnName,
                goodsRemark = i.GoodsNumber,
                goodsSum = i.Quantity.ToString(),
                goodsUnitPrice = i.DeclareFee.ToString("F2")
            }).ToList();
            return result;
        }

        private string CreateSignature(string refNo, string businessType, string shipToken, string appToken, string callingTime)
        {
            string raw = $"{shipToken}{appToken}{callingTime}{refNo}{businessType}";
            return MD5Encrypt(raw);
        }

        public string MD5Encrypt(string strSource)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] data = Encoding.UTF8.GetBytes(strSource);
            byte[] md5data = md5.ComputeHash(data);
            md5.Clear();
            string str = "";
            for (int i = 0; i < md5data.Length; i++)
            {
                str += md5data[i].ToString("x").PadLeft(2, '0');
            }
            return str;
        }

        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            byte[] data = await Task.Run(() =>
            {
                string url = result.DownloadUrl;
                WebClient wc = new WebClient();
                var data = wc.DownloadData(url);
                return data;
            });
            return data;
        }

        private void CheckRecepient(Order_Order order)
        {

            if (string.IsNullOrWhiteSpace(order.ReceiverStreet))
                throw new Exception($"收件人街道不能为空");
            if (!order.ReceiverStreet.IsASCII())
                throw new Exception($"收件人街道包含非ASCII的特殊字符");
            if (string.IsNullOrEmpty(order.ReceiverCity))
                throw new Exception($"收件人城市不能为空");
            if (!order.ReceiverCity.IsASCII())
                throw new Exception($"收件人城市包含非ASCII的特殊字符");
            if (string.IsNullOrWhiteSpace(order.ReceiverCountryCode)
                || !order.ReceiverCountryCode.IsASCII()
                || order.ReceiverCountryCode.Length > 2
                )
            {
                throw new Exception($"收件人国家代码必须为二字简码");
            }
            if (!string.IsNullOrEmpty(order.ReceiverEmail) && order.ReceiverEmail.Length > 255)
                throw new Exception($"收件人邮箱不能超过255个字符");
            if (string.IsNullOrWhiteSpace(order.ReceiverName))
                throw new Exception($"收件人姓名不能为空");
            if (!Regex.IsMatch(order.ReceiverName, @"^[a-z0-9A-Z\ \-\.]{1,35}$"))
                throw new Exception($"收件人姓名只能是字母或数字并且不能超过35个字符");
            if (!string.IsNullOrWhiteSpace(order.ReceiverPhone) && order.ReceiverPhone.Length > 35)
                throw new Exception($"收件人电话不能超过35个字符");

            if (string.IsNullOrWhiteSpace(order.ReceiverState))
                throw new Exception($"收件人省州不能为空");
            if (order.ReceiverCountryCode == "US" && order.ReceiverState.Length != 2)
                throw new Exception($"收件人省州必须为二字代码");

            if (string.IsNullOrWhiteSpace(order.ReceiverZipCode))
                throw new Exception($"收件人邮编不能为空");
            //if (order.ReceiverZipCode.Length != 5)
            //    throw new Exception($"收件人邮编长度必须为5");
        }

        public Task<string> GetTrackingNumber(string SystemNo, string TrackingNumber, string ServiceOrderNo, Logistics_Channel channel)
        {
            throw new NotImplementedException();
        }
    }
}
