using Microsoft.Extensions.Caching.Distributed;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XYY.Model.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.Base;
using XYY.Service.Standard.ChannelApi.SekoSingleSPApi.Model;

namespace XYY.Service.Standard.ChannelApi.SekoSingleSPApi
{
    public partial class Api : IBaseApi
    {
        #region 构造
        IDistributedCache _distributedCache;
        public Api(IDistributedCache distributedCache)
        {
            _distributedCache = distributedCache;
        }
        #endregion
        #region 私有
        public string ServiceName => "SekoSingleSP";
        const string ChannelCacheKey = "@@ChannelCacheKey";
        private string GetToken(string ApiKey,string ApiSecret, string ApiHost)
        {

            string userName = ApiKey;
            string password = ApiSecret;


            RestClient client = new RestClient(ApiHost);
            RestRequest req = new RestRequest("Tokens");
            req.Method = Method.POST;
            req.AddHeader("content-type", "application/x-www-form-urlencoded");
            req.AddParameter("username", userName, ParameterType.GetOrPost);
            req.AddParameter("password", password, ParameterType.GetOrPost);
            var tokenResult = client.Execute<SekoTokenInfo>(req);
            if (tokenResult.StatusCode == System.Net.HttpStatusCode.OK)
            {
                SekoTokenInfo tokenInfo = tokenResult.Data;
                if (tokenInfo == null)
                {
                    throw new Exception("API返回TOKEN无效");
                }
                else
                {
                    return tokenInfo.access_token;
                }
            }
            else
            {
                string msg = string.IsNullOrWhiteSpace(tokenResult.ErrorMessage) ? tokenResult.Content : tokenResult.ErrorMessage;
                throw new Exception($"请求TOKEN报错:{msg}");
            }
        }
        private SekoSingle_CreateOrderResponse CreateOrder(string token, Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel)
        {
            SekoSingle_CreateOrderParam param = CreateOrderParam(order, goods, channel);
            RestClient client = new RestClient(channel.ApiHost);
            RestRequest req = new RestRequest("Parcels/Single", Method.POST);
            req.AddHeader("authorization", $"Bearer {token}");
            req.AddJsonBody(param);
            var response = client.Execute<SekoSingle_CreateOrderResponse>(req);

            SekoSingle_CreateOrderResponse data = response.Data;
            if (data == null)
            {
                string msg = response.Content;
                throw new Exception($"API返回数据为空或不符合格式:{msg}");
            }
            if (data.isSuccess == true)
            {
                return data;
            }
            else
            {
                string msg = data.message;
                throw new Exception($"下单出错 {msg}");
            }
        }
        private SekoSingle_CreateOrderParam CreateOrderParam(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel)
        {
            string serviceCode = channel.ServiceChannelCode;
            SekoSingle_Consignee consignee = new SekoSingle_Consignee
            {
                city = order.ReceiverCity,
                company = order.ReceiverCompany,
                countryCode = order.ReceiverCountryCode,
                email = order.ReceiverEmail,
                name = order.ReceiverName,
                phone = order.ReceiverPhone,
                postalCode = order.ReceiverZipCode,
                province = order.ReceiverState,
                street1 = order.ReceiverStreet,
            };
            SekoSingle_Dimension dimension = new SekoSingle_Dimension
            {
                height = (double)order.Height,
                length = (double)order.Length,
                width = (double)order.Width,
                unit = "CM"
            };
            List<SekoSingle_LineInfosItem> lineInfos = CreatelineInfos(goods);
            SekoSingle_Shipper shipper = new SekoSingle_Shipper
            {
                city = channel.SenderCity,
                company = channel.SenderCompany,
                countryCode = channel.SenderCountryCode,
                district = string.Empty,
                email = channel.SenderEmail,
                name = channel.SenderName,
                phone = channel.SenderPhone,
                postalCode = channel.SenderZipCode,
                province = channel.SenderState,
                street1 = channel.SenderStreet
            };
            SekoSingle_Weight weight = new SekoSingle_Weight
            {
                unit = "G",
                value = order.OPWeight <= 0 ? order.CustomerWeight : order.OPWeight,
            };
            SekoSingle_Parcel parcel = new SekoSingle_Parcel
            {
                consignee = consignee,
                dimension = dimension,
                distInfo = null,
                idCardNbr = null,
                lineInfos = lineInfos,
                pickingInfos = null,
                weight = weight,
                shipper = shipper,
                poa = "LAX",
                orderNbr = order.SystemNo,
                additionalReferences = null
            };

            SekoSingle_CreateOrderParam param = new SekoSingle_CreateOrderParam
            {
                serviceCode = serviceCode,
                parcel = parcel
            };
            return param;
        }
        private List<SekoSingle_LineInfosItem> CreatelineInfos(List<Order_OrderGoods> orderGoods)
        {
            List<SekoSingle_LineInfosItem> result = new List<SekoSingle_LineInfosItem>();

            var goodsGroup = orderGoods.GroupBy(g => g.EnName);

            foreach (var g in goodsGroup)
            {
                var goodsItem = g.First();
                var goodsCount = g.Sum(i => i.Quantity);
                var totalValue = g.Sum(i => i.DeclareFee * i.Quantity);
                SekoSingle_LineInfosItem item = new SekoSingle_LineInfosItem
                {
                    quantity = goodsCount,
                    goodsInfo = new SekoSingle_GoodsInfo
                    {
                        brand = null,
                        hsCode = goodsItem.HsCode,
                        localName = goodsItem.CnName,
                        name = goodsItem.EnName,
                        sku = goodsItem.GoodsNumber,
                        model = goodsItem.GoodsNumber,
                        spec = string.Empty
                    },
                    lineTotal = new SekoSingle_LineTotal
                    {
                        unit = goodsItem.DeclareCurrency,
                        value = totalValue
                    }
                };
                result.Add(item);
            }
            return result;
        }
        private LabelResult GetLabelInfo(string token, string apiHost, string trackingNbr)
        {
            RestClient client = new RestClient(apiHost);
            string src = $"/Parcels/Label/{trackingNbr}";
            RestRequest req = new RestRequest(src, Method.GET);
            req.AddHeader("authorization", $"Bearer {token}");
            req.AddHeader("Content-Type", "application/json");
            var response = client.Execute<GetLabelResult>(req);

            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var result = response.Data;
                if (result == null)
                {
                    string msg = "获取单号API返回响应为空 ";
                    if (!string.IsNullOrWhiteSpace(response.Content))
                    {
                        msg += response.Content;
                    }

                    throw new Exception(msg);
                }
                else
                {
                    if (!result.isSuccess)
                    {
                        var msg = "获取单号API返回错误:" + result.message;

                        if (string.IsNullOrWhiteSpace(result.message))
                        {
                            msg += response.Content;
                        }

                        throw new Exception(msg);
                    }
                    else if (result.result == null)
                    {
                        string msg = "获取单号API返回数据为空";
                        throw new Exception(msg);
                    }
                    else
                    {
                        return result.result;
                    }

                }
            }
            else
            {
                string msg = "API获取单号失败:" + (string.IsNullOrEmpty(response.ErrorMessage) ? response.Content : response.ErrorMessage);
                throw new Exception(msg);
            }
        }
        private byte[] DownLabel(string downloadUrl)
        {
            byte[] data = null;
            System.Net.WebClient client = new System.Net.WebClient();
            for (int i = 0; i < 3; i++)
            {
                data = client.DownloadData(new Uri(downloadUrl));
                if (data.Length > 3 * 1024)
                {
                    //面单大于5k时返回
                    break;
                }
                //3秒后重试一次
                System.Threading.Thread.Sleep(3 * 1000);
            }
            if (data == null || data.Length < 3 * 1024)
            {
                throw new Exception("面单获取失败，请稍候重试");
            }
            return data;
        }

        #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)
        {
            string url = model.ApiHost;
            url = "https://api.onepizza.net/";
            string path = $"Parcels/Void/?trackingNbr={model.TrackingNumber}";
            var token = GetToken(model.ApiKey,model.ApiSecret,model.ApiHost);
            RestClient client = new RestClient(url);
            RestRequest req = new RestRequest(path, Method.GET);
            req.AddHeader("authorization", $"Bearer {token}");

            var resp = client.Execute<SekoApiResult<SekoSingle_CanelOrderResponse>>(req);
            if (resp.StatusCode == System.Net.HttpStatusCode.OK && resp.Data != null)
            {
                if (!resp.Data.isSuccess)
                {
                    string errMsg = resp.Data.message;
                    if (string.IsNullOrWhiteSpace(errMsg) && resp.Data.result?.result?.errors?.Any() == true)
                    {
                        errMsg = string.Join(",", resp.Data.result?.result?.errors);
                    }
                    model.ResponseCode= ((int)resp.StatusCode).ToString();
                    model.ResultMessage = errMsg;
                    throw new Exception($"取消订单时出错:{errMsg}");
                }
            }
        }

        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 token = GetToken(channel.ApiKey, channel.ApiSecret, channel.ApiHost);
            string apiHost = channel.ApiHost;

            var result = CreateOrder(token, order, goods, channel);



            var trackingNumber = result.result.trackingNbr;
            var orderNbr = result.result.orderNbr;
            var port = result.result.poa;
            return new UploadResult
            {
                destinationCode = port,
                ServiceOrderNumber = orderNbr,
                IsSuccess = true,
                TrackingNumber = trackingNumber,
                TransferNumner = order.TransferNumber,
                LazyDownloadLabel = true,
                ServiceOrderNumber3 = token,//token保存在这里，下单面单时不用重新获取
                DownloadUrl = trackingNumber
            };
        }

        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            string token = result.ServiceOrderNumber3;
            string trackingNumber = result.TrackingNumber;

            if (string.IsNullOrEmpty(trackingNumber))
            {
                throw new Exception("获取面单报错:渠道跟踪号为空");
            }

            var labelResult = GetLabelInfo(token, channel.ApiHost, trackingNumber);
            if (!string.IsNullOrWhiteSpace(labelResult.labelUrl))
            {
                byte[] data = DownLabel(labelResult.labelUrl);
                return data;
                //string pdfDir = Path.Combine(channel.LableDir, DateTime.Now.ToString_yyyyMMdd());
                //if (!Directory.Exists(pdfDir))
                //{
                //    Directory.CreateDirectory(pdfDir);
                //}
                //using (FileStream fs = new FileStream(Path.Combine(pdfDir, $"{result.TrackingNumber}.pdf"), FileMode.Create))
                //{
                //    fs.Write(data, 0, data.Length);
                //    fs.Flush();
                //}
                //return Path.Combine(pdfDir, $"{result.TrackingNumber}.pdf");
            }
            else
                throw new Exception("获取面单报错:面单地址为空");
        }

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