using Org.BouncyCastle.Asn1.Crmf;
using RestSharp;
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.Model.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.Base;

namespace XYY.Service.Standard.ChannelApi.Sengi
{
    public class Api : IBaseApi
    {
        public string ServiceName => "SENGI-E2E";
        string createOrderUri = "/di-order/create";
        string labelUri = "/e2e-order/gen-labe";


        private string CreateToken(string customerId, string secret)
        {
            string raw = $"{customerId}&{secret}";
            var bytes = Encoding.UTF8.GetBytes(raw);
            string token = Convert.ToBase64String(bytes);
            return token;
        }

        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 Task<List<string>> Confims(List<OrderConfimRequest> order, Logistics_Channel channel)
        {
            throw new NotImplementedException();
        }

        private bool HasChinese(string content)
        {
            //判断是不是中文
            string regexstr = @"[\u4e00-\u9fa5]";
            if (Regex.IsMatch(content, regexstr))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public async Task<UploadResult> DataUpload(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel, ExtendArg arg)
        {
            RootParam rootParam = createRootParam(order, goods, channel);
            var j = Newtonsoft.Json.JsonConvert.SerializeObject(rootParam);
            var response = await Send(channel, rootParam, createOrderUri);
            if (response.StatusCode != System.Net.HttpStatusCode.OK)
            {
                throw new Exception($"错误:{response.Content}");
            }
            else
            {
                var json = response.Content;
                RootResponse resp = null;
                try
                {
                    resp = Newtonsoft.Json.JsonConvert.DeserializeObject<RootResponse>(json);
                    if (resp == null)
                        throw new Exception("解析API结果为空");
                }
                catch (Exception ex)
                {
                    throw new Exception($"解析API结果失败:{ex.Message} {response.Content}");
                }
                if (resp.code != 100)
                {
                    string msg = resp.message;
                    if (!string.IsNullOrWhiteSpace(resp.item?.errorMessage))
                    {
                        msg += resp.item?.errorMessage;
                    }
                    if (!string.IsNullOrEmpty(msg))
                    {
                        throw new Exception($"API返回失败，Code:{resp.code},Msg:{msg}");
                    }
                }
                if (resp.item == null || string.IsNullOrEmpty(resp.item.trackingNumber))
                {
                    throw new Exception($"API返回跟踪号为空");
                }

                string trackingNum = resp.item.trackingNumber;
                string labelUrl = resp.item.labelUrl;

                UploadResult result = new UploadResult
                {
                    DownloadUrl = labelUrl,
                    IsSuccess = true,
                    TrackingNumber = trackingNum
                };
                return result;
            }
        }

        private RootParam createRootParam(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel)
        {
            int weight = order.OPWeight > 0 ? order.OPWeight : order.CustomerWeight;
            decimal weightKg = weight / 1000m;
            List<ContentListItem> goodsList = createGoodsList(goods);
            Receiver receiver = createReceiver(order);
            Sender sender = createSender(order);
            Parcel parcel = createParcel(weightKg, goodsList, sender, receiver);
            RootParam rootParam = new RootParam
            {
                customerOrderNumber = order.TransferNumber,
                prodCode = channel.ServiceChannelCode,
                declareTypeCode = 4,
                insuranceCoverage = 0,
                insuranceCurrency = "RMB",
                iossNumber = "IM0123456789",//本API只负责派送服务，不包含清关，不需要给IOSS，但IOSS又是必填//order.ioss,
                codValue = 0,
                codValueCurrency = null,
                dutyTerm = "DDU",
                shippingFee = 0.00m,
                shippingFeeCurrency = "EUR",
                depot = "CAN03",
                parcel = parcel,

            };

            if (order.CustomerId == 676)
            {
                rootParam.customerOrderNumber = order.CustomerOrderNo;
            }

            return rootParam;
        }

        private List<ContentListItem> createGoodsList(List<Order_OrderGoods> goods)
        {
            var goodsList = new List<ContentListItem>();
            foreach (var g in goods)
            {
                decimal weight = g.Weight / 1000m;
                if (weight == 0) weight = 0.1m;
                if (!HasChinese(g.CnName))
                {
                    throw new Exception("中文品名必须包含至少一个中文字符");
                }
                ContentListItem item = new ContentListItem
                {
                    eName = g.EnName,
                    hsCode = g.HsCode,
                    origName = g.CnName,
                    productUrl = null,
                    quantity = g.Quantity,
                    sku = g.GoodsNumber,
                    unitPrice = g.DeclareFee,
                    unitPriceCurrency = g.DeclareCurrency,
                    unitWeight = weight
                };
                goodsList.Add(item);
            }
            return goodsList;
        }

        private Parcel createParcel(decimal weight, List<ContentListItem> contentList, Sender sender, Receiver receiver)
        {
            Parcel parcel = new Parcel()
            {
                length = 0,
                width = 0,
                height = 0,
                weight = weight,
                labelAccess = "PDF",
                markNo = null,
                contentList = contentList,
                sender = sender,
                receiver = receiver
            };
            return parcel;
        }


        private Sender createSender(Order_Order order)
        {
            Sender sender = new Sender()
            {
                countryCode = "CN",
                firstName = "Gao Zhuo",
                lastName = null,
                company = "XYY",
                street = "Block A Floor 5, shixia road 8, baiyunhu street, baiyun, guangzhou",
                city = "GuangZhou",
                province = "GuangDong",
                zipCode = "510000",
                phoneAreaCode = null,
                phone = "18588532219",
                houseNumber = null,
                senderCode = null
            };
            return sender;
        }

        private Receiver createReceiver(Order_Order order)
        {
            if (order.ReceiverStreet.Length > 40)
                throw new Exception("街道地址不能超过40个字符");

            string province = null;
            if (string.IsNullOrEmpty(order.ReceiverState))
                throw new Exception("必须传入州省");
            if (order.ReceiverState.Length > 2)
            {
                bool ok = tryGetProvinceCode(order.ReceiverState, out province);
                if (!ok)
                {
                    throw new Exception("省州必须填写2字简称");
                }
            }
            else province = order.ReceiverState.ToUpper();

            Receiver receiver = new Receiver
            {
                countryCode = order.ReceiverCountryCode,
                firstName = order.ReceiverName,
                lastName = null,
                company = null,
                street = order.ReceiverStreet,
                city = order.ReceiverCity,
                email = order.ReceiverEmail,
                province = province,
                zipCode = order.ReceiverZipCode,
                phoneAreaCode = null,
                phone = order.ReceiverPhone,
                houseNumber = null,
                receiverCode = null
            };
            return receiver;
        }

        private bool tryGetProvinceCode(string receiverState, out string provinceCode)
        {
            string prov = receiverState.ToUpper();
            if (Provinces.ProvinceCodes.TryGetValue(prov, out string code))
            {
                provinceCode = code;
                return true;
            }
            else
            {
                provinceCode = null;
                return false;
            }
        }

        private async Task<IRestResponse> Send(Logistics_Channel channel, object body, string uri)
        {
            string key = channel.ApiKey;
            string secret = channel.ApiSecret;
            string host = channel.ApiHost;
#if DEBUG
            //key = "C10003";
            //secret = "dPZ2KRS6erQ=";
            //host = "https://sengiexpress.com/test-api/2";
#endif

            string token = CreateToken(key, secret);

            RestClient restClient = new RestSharp.RestClient(host);
            if (uri.StartsWith("https://"))
                restClient = new RestClient();
            RestRequest request = new RestRequest(uri, Method.POST);
            request.AddJsonBody(body);
            request.AddHeader("Authorization", $"Basic {token}");//$"Basic {token}")

            var respone = await restClient.ExecuteAsync(request);
            return respone;
        }

        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            //https://sengiexpress.com/api-v2/e2e-order/gen-label
            if (string.IsNullOrEmpty(result.DownloadUrl))
            {
                var r = await Send(channel, new { orderNumber = order.SystemNo },labelUri);
                if (r.StatusCode == HttpStatusCode.OK)
                {
                    LabelRoot labelRoot = Newtonsoft.Json.JsonConvert.DeserializeObject<LabelRoot>(r.Content);
                    result.DownloadUrl = labelRoot.item.labelUrl;
                }
                else
                {
                    throw new Exception(r.ErrorMessage ?? r.Content);
                }
            }

            byte[] data = await Task.Run(() =>
            {
                string url = result.DownloadUrl;
                WebClient wc = new WebClient();
                var data = wc.DownloadData(url);
                return data;
            });
            return data;
        }

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

        //如果好用，请收藏地址，帮忙分享。
        public class LabelItem
        {
            /// <summary>
            /// 
            /// </summary>
            public string customerOrderNumber { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string labelUrl { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string trackingNumber { get; set; }
        }

        public class LabelRoot
        {
            /// <summary>
            /// 
            /// </summary>
            public int code { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public Item item { get; set; }
            /// <summary>
            /// 提交成功
            /// </summary>
            public string message { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string timeStamp { get; set; }
        }

    }
}
