using Microsoft.Extensions.Caching.Distributed;
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.Common.Standard;
using XYY.Model.Standard.MpsOrder;
using XYY.Core.Standard.PDF;

namespace XYY.Service.Standard.ChannelApi.YoujiYouni
{
    public class Api : IBaseApi
    {
        /*
         * api文档地址：http://doc.8c15.com/web/#/12?page_id=42
         */
        Microsoft.Extensions.Caching.Distributed.IDistributedCache Cache;

        public Api(IDistributedCache cache)
        {
            Cache = cache;
        }

        /// <summary>
        /// 数字签名
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="noceStr"></param>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        private string GetSign(Logistics_Channel channel, string noceStr, long timestamp)
        {
            string strWaitSign = $"{channel.ApiKey}+{noceStr}+{channel.ApiSecret}+{timestamp}";
            return XYY.Common.Standard.String.Encryption.Md532(strWaitSign).ToLower();

        }
        string tokenKey = "YoujiYouni";
        private async Task<string> GetCacheToken(Logistics_Channel channel)
        {
            //return await this.Cache.GetAsync(tokenKey, async () =>
            //{
            return await GetApiToken(channel);
            //}, new DistributedCacheEntryOptions { SlidingExpiration = new TimeSpan(0, 10, 0) });
        }

        private async Task<T> Post<T>(object o, string method, Logistics_Channel channel)
        {
            RestSharp.RestClient client = new RestSharp.RestClient(channel.ApiHost);
            RestSharp.RestRequest request = new RestSharp.RestRequest(method, RestSharp.Method.POST);
            string token = await GetCacheToken(channel);
            request.AddHeader("Access-Token", token);
            request.AddJsonBody(o);
            string josn = Newtonsoft.Json.JsonConvert.SerializeObject(o);
            var response = client.Execute(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var d = Newtonsoft.Json.JsonConvert.DeserializeObject<Result<T>>(response.Content);
                if (d.meta.code == 0)
                    return d.response;
                else
                    throw new Exception(d.meta.msg);
            }
            else
                throw new Exception(response.ErrorMessage ?? response.Content);

        }

        /// <summary>
        /// 获取token
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        private async Task<string> GetApiToken(Logistics_Channel channel)
        {
            long timestamp = Timestamp.GetUnix();
            string noceStr = Guid.NewGuid().ToString().Replace("-", "");
            string sign = GetSign(channel, noceStr, timestamp);
            var postData = new
            {
                pk = channel.ApiKey,
                onceStr = noceStr,
                timestamp = timestamp,
                sign = sign
            };
            RestSharp.RestClient client = new RestSharp.RestClient(channel.ApiHost);
            RestSharp.RestRequest request = new RestSharp.RestRequest("v1/oauth/access-token", RestSharp.Method.POST);
            request.AddJsonBody(postData);
            var response = client.Execute(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                Result<TokenResult> result = Newtonsoft.Json.JsonConvert.DeserializeObject<Result<TokenResult>>(response.Content);
                if (result.meta.code > 0)
                    throw new Exception(result.meta.msg);
                else
                    return result.response.AccessToken;
            }
            else
                throw new Exception(response.ErrorMessage ?? response.Content);
        }

        public class Result<T>
        {
            public ResultMeta meta
            {
                get; set;
            }

            public T response { get; set; }
        }

        public class TokenResult
        {
            [Newtonsoft.Json.JsonProperty(PropertyName = "access-token")]
            public string AccessToken
            {
                get; set;
            }

            public int expire_in
            {
                get; set;
            }
        }

        public class ResultMeta
        {
            public int code
            {
                get; set;
            }

            public string msg
            {
                get; set;
            }

            public string request_uri
            {
                get; set;
            }
        }

        public string ServiceName => "YoujiYouni";

        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();
        }



        public async Task<UploadResult> DataUpload(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel, ExtendArg arg)
        {
            try
            {
                var request = CreateReqeust(order, channel, goods, arg.Order);
                var res = await Post<OrderResult>(request, "v1/order/create", channel);
                if (channel.ServiceChannelCode != "33")
                {
                    return new UploadResult
                    {
                        IsSuccess = true,
                        MPSTrackings = res.shipments.ToDictionary(x => x.case_number, x => x.track_no),
                        TrackingNumber = res.shipments[0].track_no,
                        DownloadUrl = res.shipments[0].label
                    };
                }
                else
                {
                    return new UploadResult
                    {
                        IsSuccess = true,
                        MPSTrackings = res.shipments.ToDictionary(x => x.case_number, x => x.track_no),
                        TrackingNumber = res.shipments[0].track_no,
                        DownloadUrl = String.Join(',', res.shipments.Select(x => x.label))
                    };
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private class OrderResultShipmentsItem
        {
            /// <summary>
            /// 
            /// </summary>
            public int id { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string case_number { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string track_no { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string label { get; set; }
        }

        private class OrderResult
        {
            /// <summary>
            /// 
            /// </summary>
            public int order_id { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public List<OrderResultShipmentsItem> shipments { get; set; }
        }

        private object CreateReqeust(Order_Order order, Logistics_Channel channel, List<Order_OrderGoods> goods, Order_MpsOrder mpsOrder)
        {
            int i = 1;
            string street = order.ReceiverStreet.Replace("\r", " ").Replace("\n", " ").Replace("\r\n", " ");
            string[] streetArray = street.ToArray(35);
            if (streetArray.Length > 2)
                throw new Exception("收件人地址超长");
            if (order.CustomerWeight < 10 * 1000)
                order.CustomerWeight = 10 * 1000;
            return new
            {
                line_id = int.Parse(channel.ServiceChannelCode),
                customer_ref = order.CustomerOrderNo,
                is_charged = 0,
                package_type = string.Empty,
                fba_warehouse_code = "",
                sender = new
                {
                    country_code = channel.SenderCountryCode,
                    full_name = channel.SenderName,
                    city = channel.SenderCity,
                    post_code = channel.SenderZipCode,
                    phone = channel.SenderPhone,
                    address1 = channel.SenderStreet
                },
                consignee = new
                {
                    post_code = order.ReceiverZipCode,
                    address1 = streetArray[0],
                    address2 = streetArray.Length > 1 ? streetArray[1] : String.Empty,
                    full_name = order.ReceiverName,
                    phone = string.IsNullOrEmpty(order.ReceiverPhone) ? "1111" : order.ReceiverPhone,//补空电话
                    email = order.ReceiverEmail,
                    province = order.ReceiverState,
                    city = order.ReceiverCity,
                    country_code = order.ReceiverCountryCode,
                    fba_warehouse_code = mpsOrder.WarehouseCode
                },
                shipments = mpsOrder.Boxs.Select(y =>
                new
                {
                    length = y.OpLength,
                    height = y.OpHeight,
                    width = y.OpWidth,
                    weight = y.OpInputWeight,
                    case_number = y.BoxNumber,
                    goods = y.Goods.Select(x => new
                    {

                        customs_currency = x.Currency,
                        customs_price = x.GoodsValue.ToString("0.00"),
                        hs_code = x.HsCode,
                        name = x.CnName,
                        name_en = x.EnName,
                        num = x.Quantity,
                        origin = "cn"
                    })
                })
            };
        }



        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            if (!string.IsNullOrEmpty(result.DownloadUrl))
            {
                //包含逗号分隔的Url
                List<byte[]> Datas = new List<byte[]>();
                foreach (var item in result.DownloadUrl.Split(','))
                {
                    System.Net.WebClient client = new System.Net.WebClient();
                    int i = 0;
                    while (i < 3)
                    {
                        try
                        {

                            i++;
                            var d = client.DownloadData(item);
                            if (d.Length > 5000)
                            {
                                Datas.Add(d);
                                break;
                            }

                        }
                        catch (Exception ex)
                        {

                        }
                        finally
                        {
                            System.Threading.Thread.Sleep(3000);
                        }
                    }
                }
                if (Datas.Count == 1)
                    return Datas[0];
                else if (Datas.Count > 1)
                {
                    string tempDict = System.IO.Path.Combine(System.AppContext.BaseDirectory, "temp");
                    if (!System.IO.Directory.Exists(tempDict))
                        System.IO.Directory.CreateDirectory(tempDict);
                    string tempFilePath = System.IO.Path.Combine(tempDict, result.TrackingNumber + ".pdf");
                    PDFHelper.MergePDFFiles(tempFilePath, Datas, false);
                    var margeDatas = System.IO.File.ReadAllBytes(tempFilePath);
                    System.IO.File.Delete(tempFilePath);
                    return margeDatas;
                }
                else
                {
                    throw new Exception("面单下载失败，一张面单都未下载成功");
                }
            }
            else
            {
                throw new Exception("面单下载失败，面单下载地址未返回");
            }
        }

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