using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using XYY.Model.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.Base;
using XYY.Service.Standard.ChannelApi.LanQiAPI.Model;

namespace XYY.Service.Standard.ChannelApi.LanQiAPI
{
    public partial class Api : IBaseApi
    {
        #region 构造
        public Api()
        {

        }
        #endregion
        #region 私有
        public string ServiceName => "LanQi";
        string wareHouseCode = "GZ1";
        /// <summary>
        /// 蓝鳍的国家-服务代码对照
        /// </summary>
        private List<Tuple<string, string>> countryChannelCodeMapping = new List<Tuple<string, string>>
        {
            new Tuple<string, string>("SA","682001"),//沙特中东小包-普货
            new Tuple<string, string>("AE","784001"),
            new Tuple<string, string>("KW","414001"),
            new Tuple<string, string>("BH","048001"),
            new Tuple<string, string>("OM","512001"),
            new Tuple<string, string>("QA","634001"),
            new Tuple<string, string>("MA","504001"),
            new Tuple<string, string>("IL","376021"),
        };
        public long DateTimeToLongTimeStamp()
        {
            var now = DateTime.UtcNow;
            long stamp = new DateTimeOffset(now).ToUnixTimeMilliseconds();
            return stamp;
        }
        private CreateOrderParam CreateOrderParamModel(Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods, long requestTimeStamp)
        {
            OrderParam orderParam = CreateOrderModel(channel, order, orderGoods);
            string serviceChannelCode = GetServiceChannelCode(order.ReceiverCountryCode);
            string sign = CreateCreateOrderSignV2(channel.ApiKey, requestTimeStamp, channel.ApiSecret, order.TransferNumber, serviceChannelCode);
            CreateOrderParam param = new CreateOrderParam
            {
                customerCompanyCode = channel.ApiKey,// "660107",
                requestTimestamp = requestTimeStamp,
                param = orderParam,
                sign = sign
            };
            return param;
        }
        private string CreateCreateOrderSignV2(string customerCompanyCode, long requestTimestamp, string accessKey, string orderCode, string lanqichannel)
        {
            string warehouseCode = this.wareHouseCode;
            string raw = $"{customerCompanyCode}{requestTimestamp}{accessKey}{lanqichannel}{orderCode}{warehouseCode}{customerCompanyCode}";
            string sign = Encrypt(raw);
            return sign;
        }
        private string Encrypt(string raw)
        {
            string sign1 = ConvertStringToMD5(raw);
            string sign = ConvertStringToMD5(sign1);
            return sign;
        }
        public string ConvertStringToMD5(string ClearText)
        {

            byte[] ByteData = Encoding.UTF8.GetBytes(ClearText);
            MD5 oMd5 = MD5.Create();
            byte[] HashData = oMd5.ComputeHash(ByteData);
            StringBuilder oSb = new StringBuilder();

            for (int x = 0; x < HashData.Length; x++)
            {
                oSb.Append(HashData[x].ToString("X2"));
            }
            return oSb.ToString();
        }
        private OrderParam CreateOrderModel(Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            var value = orderGoods.Sum(i => i.DeclareFee * i.Quantity);
            var weight = order.CustomerWeight / 1000.00d;
            if (weight <= 0)
            {
                weight = orderGoods.Sum(i => i.Weight * i.Quantity) / 1000.00d;
            }
            var totalQty = orderGoods.Sum(i => i.Quantity);

            var lanqiChannelCode = GetServiceChannelCode(order.ReceiverCountryCode);
            if (string.IsNullOrWhiteSpace(lanqiChannelCode))
                throw new Exception("找不到该国家对应的渠道服务代码");
            ConsigneeInfo consigneeInfo = CreateConsigneeInfo(order);
            var consignorInfo = CreateConsignorInfo(channel);
            var skuInfoList = CreateSkuList(order, orderGoods);
            OrderParam orderParam = new OrderParam
            {
                collectingMoneyAmount = 0.0m,
                consigneeInfo = consigneeInfo,
                consignorInfo = consignorInfo,
                customerPackageWeight = weight,
                customsClearance = "普货",
                declaredValue = (int)value,
                deliveryType = 100,
                goodsTotalQuantity = totalQty,
                hasBattery = false,
                lanqiChannel = lanqiChannelCode,
                wareHouseCode = wareHouseCode,
                orderCode = order.TransferNumber,
                orderType = 100,
                packageQuantity = 1,
                //packageVolume = null,
                payType = 100,
                //prepaidAmount = null,
                //prepaidCurrency = null,
                skuInfoList = skuInfoList
            };
            if (order.CodFee > 0)
            {
                orderParam.payType = 200;
                orderParam.collectingMoneyAmount = order.CodFee;
            }

            return orderParam;
        }
        private string GetServiceChannelCode(string countryCode)
        {
            countryCode = countryCode?.ToUpper();
            string lanqiChannelCode = countryChannelCodeMapping.FirstOrDefault(i => i.Item1 == countryCode)?.Item2;
            return lanqiChannelCode;
        }
        private ConsigneeInfo CreateConsigneeInfo(Order_Order order)
        {
            ConsigneeInfo consigneeInfo = new ConsigneeInfo
            {
                addressLine1 = order.ReceiverStreet,
                addressLine2 = string.Empty,
                addressType = 200,
                city = order.ReceiverCity,
                //company = order.ReceiverCompany,
                consigneeUserName = order.ReceiverName ?? string.Empty,
                country = order.ReceiverCountryCode?.ToUpper(),
                //district = null,
                documentId = order.TaxNo ?? string.Empty,
                //email = order.ReceiverEmail,
                //landMark = null,
                //latitude = null,
                //longitude = null,
                phone = order.ReceiverPhone ?? string.Empty,
                state = order.ReceiverState,
                //streetNumber = order.House,
                tel = order.ReceiverPhone ?? string.Empty,
                zipCode = order.ReceiverZipCode ?? string.Empty
            };

            return consigneeInfo;
        }
        private ConsignorInfo CreateConsignorInfo(Logistics_Channel channel)
        {
            ConsignorInfo consignorInfo = new ConsignorInfo
            {
                consignor = "xingyunyi01",// channel.SenderName
            };
            return consignorInfo;
        }
        private List<SkuInfoList> CreateSkuList(Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            List<SkuInfoList> list = new List<SkuInfoList>();

            foreach (var g in orderGoods)
            {
                double weight_g = g.Weight;
                if (weight_g <= 0)
                {
                    int totalQty = orderGoods.Sum(i => i.Quantity);
                    weight_g = (order.CustomerWeight / (totalQty <= 0 ? 1 : totalQty));
                }
                if (g.DeclareCurrency == "SAR")
                {
                    g.DeclareFee = (g.DeclareFee / (decimal)3.751);
                }
                if (g.DeclareCurrency == "AED")
                {
                    g.DeclareFee = (g.DeclareFee / (decimal)3.6728);
                }
                else if (g.DeclareCurrency != "USD")
                {
                    throw new Exception("申报币种仅支持USD、SAR、AED");
                }
                SkuInfoList sku = new SkuInfoList
                {
                    declaredValue = (int)Math.Round(g.DeclareFee),
                    goodsDescription = g.GoodsNumber ?? string.Empty,
                    sku_code = g.GoodsNumber ?? string.Empty,
                    //height = null,
                    hsCode = g.HsCode ?? string.Empty,
                    invoiceChineseName = g.CnName ?? string.Empty,
                    invoiceEnglishName = g.EnName ?? string.Empty,
                    //length = null,
                    quantity = g.Quantity,
                    weight = weight_g / 1000.00,
                    //width = null
                };
                list.Add(sku);
            }
            return list;
        }
        /// <summary>
        /// 面单和轨迹接口加密方式通用
        /// </summary>
        /// <param name="customerCompanyCode"></param>
        /// <param name="requestTimestamp"></param>
        /// <param name="accessKey"></param>
        /// <param name="trackingNumber"></param>
        /// <returns></returns>
        private string CreateDownLabelSign(string customerCompanyCode, long requestTimestamp, string accessKey, string trackingNumber)
        {
            //string json = "{\"wayBillNumber\":\"" + trackingNumber + "\"}";
            string raw = $"{customerCompanyCode}{requestTimestamp}{accessKey}{trackingNumber}{customerCompanyCode}";
            string sign = Encrypt(raw);
            return sign;
        }
        #endregion
        #region 实现接口

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

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

        public Task<List<string>> Confims(List<OrderConfimRequest> order, Logistics_Channel channel)
        {
            throw new NotImplementedException();
        }

        public async Task<UploadResult> DataUpload(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel, ExtendArg arg)
        {
            var requestTimeStamp = DateTimeToLongTimeStamp();
            var param = CreateOrderParamModel(channel, order, goods, requestTimeStamp);
            //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            string url = channel.ApiHost;
            //RestClient client = new RestClient(url);
            var client = new RestClient(url);
            client.Timeout = -1;
            var request = new RestRequest(Method.POST);
            request.AddHeader("Content-Type", "application/json");
            
            //IRestResponse response = client.Execute(request);
            //client.ClientCertificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection();
            //client.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate());
            //RestRequest request = new RestRequest(Method.POST);
            //string json = Newtonsoft.Json.JsonConvert.SerializeObject(param);
            if (!string.IsNullOrWhiteSpace(param.param.consigneeInfo.phone) && param.param.consigneeInfo.phone == param.param.consigneeInfo.tel)
            {
                param.param.consigneeInfo.tel = null;
            }
            // request.AddJsonBody(param);
            var body = Newtonsoft.Json.JsonConvert.SerializeObject(param);
            request.AddParameter("application/json", body, ParameterType.RequestBody);
            //var resp = client.Execute<CreateOrderResponse>(request);
            var resp = client.Execute<CreateOrderResponse>(request);
            if (resp.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var respData = resp.Data;
                if (respData.status == 200)
                {
                    if (!string.IsNullOrEmpty(respData.wayBillNumber))
                    {
                        UploadResult uploadResult = new UploadResult
                        {
                            ChannelId = channel.Id,
                            DownloadUrl = null,
                            IsSuccess = true,
                            IsTransfer = false,
                            LazyDownloadLabel = false,
                            ResponseContent = resp.Content,
                            TrackingNumber = respData.wayBillNumber,
                            TransferNumner = order.TransferNumber,
                            ServiceOrderNumber = respData.wayBillNumber,

                        };
                        return uploadResult;
                    }
                    else throw new Exception("API返回无效的跟踪号");
                }
                else
                {
                    string msg = respData.description;
                    throw new Exception($"下单时API返回错误:{msg}");
                }
            }
            else
            {
                throw new Exception($"调用下单API错误:{resp.ErrorMessage}");
            }
        }

        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            long timeStamp = DateTimeToLongTimeStamp();
            string sign = CreateDownLabelSign(channel.ApiKey, timeStamp, channel.ApiSecret, order.TrackingNumber);

            RestClient client = new RestClient(channel.LabelUrl);
            RestRequest req = new RestRequest(Method.GET);
            req.AddQueryParameter("customerCompanyCode", channel.ApiKey);
            req.AddQueryParameter("requestTimestamp", timeStamp.ToString());
            req.AddQueryParameter("wayBillNumber", order.TrackingNumber);
            req.AddQueryParameter("sign", sign);

            var data = client.DownloadData(req);
            if (data == null || data.Length == 0)
                throw new Exception("下载面单结果为空");
            else
            {
                return data;
            }
        }

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