using Microsoft.Extensions.Caching.Distributed;
using XYY.Common.Standard;
using Microsoft.Extensions.Logging;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using XYY.Model.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.Base;
using Newtonsoft.Json;
using XYY.Service.Standard.ChannelApi.PPX;
using System.Net;
using System.Threading.Channels;
using System.Linq;

namespace XYY.Service.Standard.ChannelApi.SSG_USPS
{
    public partial class Api : IBaseApi
    {
        public string ServiceName => "SSGUSPS";
        const string tokenCacheKey = "@@SSGUSPS_TOKEN_CACHE_KEY";
        private static readonly object syncRoot = new object();
        ILogger<Api> _logger;
        IDistributedCache _cache;
        public Api(ILogger<Api> logger, IDistributedCache cache)
        {
            _logger = logger;
            _cache = cache;
        }

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

        public void CannelOrdersByModel(logistics_ChannelCancel logistics_ChannelCancel)
        {
            var client = new RestClient($"{logistics_ChannelCancel.ApiHost}api/service/cancel_order?client_number=" + logistics_ChannelCancel.SystemNo);
            client.Timeout = -1;
            var request = new RestRequest(Method.GET);
            string token = GetToken(logistics_ChannelCancel.ApiHost, logistics_ChannelCancel.ApiKey, logistics_ChannelCancel.ApiSecret);
            request.AddHeader("Authorization", "Bearer " + token);
            request.AddHeader("Content-Type", "application/json");
            IRestResponse response = client.Execute(request);
            string message = response.Content;
            logistics_ChannelCancel.ResultState = ResultStateEnum.成功.GetValue();
        }

        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)
        {

            //label_model=3 长短跟踪单号都返回
            var client = new RestClient($"{channel.ApiHost}api/service/create_order?product_code={channel.ServiceChannelCode.Split(";")[0]}&label_model=3");
            client.Timeout = -1;
            var request = new RestRequest(Method.POST);
            string token = GetToken(channel.ApiHost, channel.ApiKey, channel.ApiSecret);
            request.AddHeader("Authorization", "Bearer " + token);
            request.AddHeader("Content-Type", "application/json");
            var post = ConvertToDataUploadRequest(order, goods, channel, arg);
            var json = JsonConvert.SerializeObject(post);
            request.AddJsonBody(post);
            IRestResponse response = client.Execute(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var result = JsonConvert.DeserializeObject<DataUploadResult>(response.Content);
                if (result.status != 200 || result.success == "false")
                {
                    _logger.LogError("SSG_USPS下单失败:{@Request},{@Response}", request.Body, result);
                    return new UploadResult { Error = "SSG_USPS下单失败:" + response.Content };
                }
                else
                {
                    _logger.LogError("SSG_USPS下单成功:{@Response}", result);
                    return new UploadResult
                    {
                        IsSuccess = true,
                        DownloadUrl = result.response.pdf_url,
                        ServiceOrderNumber2 = result.response.tracking_no1,
                        TrackingNumber = result.response.tracking_no2,
                        ServiceOrderNumber = result.response.order_no,
                    };
                }
            }
            else
            {
                return new UploadResult { Error = "SSG_USPS下单失败:" + response.Content ?? response.ErrorMessage };
            }
        }

        public async Task<byte[]> DrawPdfLabel(Base.UploadResult result, Model.Standard.Channel.Logistics_Channel channel, Model.Standard.Order.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;
        }

        public Task<string> GetTrackingNumber(string SystemNo, string TrackingNumber, string ServiceOrderNo, Logistics_Channel channel)
        {
            throw new NotImplementedException();
        }
        public async Task<List<BagDeclareErrosResult>> BagDeclare(BagDeclareRequest bagDeclareRequest)
        {
            List<BagDeclareErrosResult> bagDeclareErrosResults = new List<BagDeclareErrosResult>();
            var list = new List<BoxDetailItem>(bagDeclareRequest.BatchDeclare.SelectMany(x => x.Value));
            List<DeclareDto> succesServerNo = new List<DeclareDto>();//记录二次推重成功的单号
            //单条处理二次推重
            foreach (var item in list)
            {
                DeclareDto dto = new DeclareDto() { ServicesOrderNo = item.ServiceNo, Weight = item.Weight, TrackingNumber = item.TrackingNumber };
                //succesServerNo.Add(dto);,IsSuccess=true 
                DeclareDto result = await UpdateWeight(dto, bagDeclareRequest.Channel);
                if (!result.IsSuccess)
                {
                    bagDeclareErrosResults.Add(new BagDeclareErrosResult()
                    {
                        TrackingNumber = result.TrackingNumber,
                        ErrorMessage = result.ErrorMessage,
                    });
                }
                else
                {
                    succesServerNo.Add(result);
                }

            }
            //预报可以批量处理
            var resultList = await ForecastOrder(succesServerNo, bagDeclareRequest.Channel);
            bagDeclareErrosResults.AddRange(resultList.Where(x => !x.IsSuccess).Select(x =>
            {
                return new BagDeclareErrosResult()
                {
                    TrackingNumber = x.TrackingNumber,
                    ErrorMessage = x.ErrorMessage,
                };
            }).ToList());
            return bagDeclareErrosResults;
        }
        #region 私有方法
        #region token获取
        /// <summary>
        /// 获取token
        /// 2小时过期
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public string GetToken(string ApiHost, string ApiKey, string ApiSecret)
        {
            string token = _cache.GetString(tokenCacheKey);

            if (!string.IsNullOrWhiteSpace(token))
            {
                return token;
            }
            else
            {
                lock (syncRoot)
                {
                    token = _cache.GetString(tokenCacheKey);
                    if (!string.IsNullOrWhiteSpace(token))
                    {
                        return token;
                    }
                    else
                    {
                        var tokenInfo = GetTokenFromApi(ApiHost, ApiKey, ApiSecret);
                        token = tokenInfo.response.token;
                        var cacheOpt = new DistributedCacheEntryOptions
                        {
                            AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2)
                        };
                        _cache.SetStringAsync(tokenCacheKey, token, cacheOpt);
                        return token;
                    }
                }
            }
        }
        private TokenInfo GetTokenFromApi(string ApiHost, string ApiKey, string ApiSecret)
        {
            var client = new RestClient($"{ApiHost}api/login/access_token?name={ApiKey}&pass={ApiSecret}");
            client.Timeout = -1;
            var request = new RestRequest(Method.GET);
            IRestResponse response = client.Execute(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var result = JsonConvert.DeserializeObject<TokenInfo>(response.Content);
                if (result.status != 200)
                {
                    throw new Exception("SSGUSPS，获取授权失败！" + result.msg);
                }
                else { return result; }
            }
            else
            {
                throw new Exception("SSGUSPS，获取授权失败！" + response.Content ?? response.ErrorMessage);
            }
        }
        #endregion
        #region xyy数据转SSG数据
        private DataUploadRequest ConvertToDataUploadRequest(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel, ExtendArg arg)
        {
            DataUploadRequest dataUploadRequest = new DataUploadRequest()
            {
                client_number = order.SystemNo,
            };
            Sender sender = new Sender()
            {
                warehouseCode = channel.ServiceChannelCode.Split(";")[1],
            };
            dataUploadRequest.sender = sender;
            List<string> address = SubstringStreet(order.ReceiverStreet);
            Receiver receiver = new Receiver()
            {
                receive_comname = order.ReceiverCompany,
                receive_name = order.ReceiverName,
                receive_telephone = order.ReceiverPhone,
                receive_mobilephone = order.ReceiverPhone,
                receive_email = order.ReceiverEmail,
                receive_state = order.ReceiverState,
                receive_city = order.ReceiverCity,
                receive_address = address[0],
                receive_address1 = address.Count > 1 ? address[1] : "",
                receive_postcode = order.ReceiverZipCode,
                receive_country_code = order.ReceiverCountryCode,
                total_packages_weight = order.CustomerWeight / 1000.0M,
            };
            dataUploadRequest.receiver = receiver;
            PackagesItem package = new PackagesItem()
            {
                weight = order.CustomerWeight / 1000.0M,
            };
            foreach (var item in goods)
            {
                Merchandise_listItem listItem = new Merchandise_listItem()
                {
                    declare_name_cn = item.CnName,
                    declare_name_en = item.EnName,
                    declare_totalfee = item.DeclareFee,
                    declare_currency = item.DeclareCurrency,
                    declare_hscode = item.HsCode,
                };
                package.merchandise_list.Add(listItem);
            }
            dataUploadRequest.packages.Add(package);
            return dataUploadRequest;
        }
        private List<string> SubstringStreet(string ReceiverStreet)
        {
            List<string> address = new List<string>() { };
            string tempstring = string.Empty;
            if (ReceiverStreet.Length > 64) { throw new Exception("SSGUSPS下单地址长度超过64位，请修改地址后重试！"); }
            if (ReceiverStreet.Length <= 32) { address.Add(ReceiverStreet); return address; }

            if (ReceiverStreet.Length > 32) { address.Add(ReceiverStreet.Substring(0, 32)); tempstring = ReceiverStreet.Substring(32, ReceiverStreet.Length - 32); }
            if (tempstring.Length > 32) { address.Add(tempstring.Substring(0, 32)); }
            else { address.Add(tempstring); }

            return address;
        }
        #endregion
        #region 预报和推重
        private async Task<DeclareDto> UpdateWeight(DeclareDto dto, Logistics_Channel channel)
        {
            string token = GetToken(channel.ApiHost, channel.ApiKey, channel.ApiSecret);
            var client = new RestClient($"{channel.ApiHost}api/service/update_weight");
            client.Timeout = -1;
            var request = new RestRequest(Method.POST);
            request.AddHeader("Authorization", $"Bearer {token}");
            request.AddHeader("Content-Type", "application/json");
            var body = @"{
" + "\n" +
            @"  ""length"": """",
" + "\n" +
            @"  ""width"": """",
" + "\n" +
            @"  ""height"": """",
" + "\n" +
            @$"  ""weight"": ""{dto.Weight / 1000.0M}"",
" + "\n" +
            @$"  ""order_number"": ""{dto.ServicesOrderNo}""
" + "\n" +
            @"}";
            request.AddParameter("application/json", body, ParameterType.RequestBody);
            IRestResponse response = client.Execute(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var result = JsonConvert.DeserializeObject<DeclareResult>(response.Content);
                if (result.status == 200 && result.success)
                {
                    dto.IsSuccess = true;
                }
                else
                {
                    dto.ErrorMessage = result.msg;
                }
            }
            else
            {
                dto.ErrorMessage = response.Content ?? response.ErrorMessage;
            }
            return dto;
        }
        private async Task<List<DeclareDto>> ForecastOrder(List<DeclareDto> declareDtos, Logistics_Channel channel)
        {
            string token = GetToken(channel.ApiHost, channel.ApiKey, channel.ApiSecret);
            var client = new RestClient($"{channel.ApiHost}api/service/forecast_order");
            client.Timeout = -1;
            var request = new RestRequest(Method.POST);
            request.AddHeader("Authorization", $"Bearer {token}");
            request.AddHeader("Content-Type", "application/json");
            request.AddJsonBody(declareDtos.Select(x => x.ServicesOrderNo).ToList());
            IRestResponse response = client.Execute(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var result = JsonConvert.DeserializeObject<DeclareResult>(response.Content);
                if (result.status != 200 || !result.success)
                {
                    declareDtos.ForEach(x => { x.IsSuccess = false; x.ErrorMessage = result.msg; });
                }
            }
            else
            {
                declareDtos.ForEach(x => { x.IsSuccess = false; x.ErrorMessage = response.Content ?? response.ErrorMessage; });
            }
            return declareDtos;
        }
        #endregion
        #endregion

    }
}
