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

namespace XYY.Service.Standard.ChannelApi.AUShipmentApi
{
    public partial class Api : IBaseApi
    {
        #region 构造
        IOrder_OrderPrintQtyRepository _orderPrintQtyRepository;
        public Api(IOrder_OrderPrintQtyRepository orderPrintQtyRepository)
        {
            this._orderPrintQtyRepository = orderPrintQtyRepository;
        }
        #endregion
        #region 私有
        public string ServiceName => "AUShipment";
        private void OrderModelJudge(Order_Order order)
        {
            if (!string.IsNullOrWhiteSpace(order.ReceiverState))
            {
                order.ReceiverState = order.ReceiverState.Trim();
            }
            if (!string.IsNullOrWhiteSpace(order.ReceiverCity))
            {
                order.ReceiverCity = order.ReceiverCity.Trim();
            }
            if (!string.IsNullOrWhiteSpace(order.ReceiverStreet))
            {
                order.ReceiverStreet = order.ReceiverStreet.Trim();
            }
        }
        private CreateOrderParam CreateOrderRequestParam(Order_Order order)
        {
            CreateOrderParam orderParam = new CreateOrderParam
            {
                orderinfo = new List<OrderInfo>{
                    new OrderInfo
                {
                    addressLine1 = order.ReceiverStreet,
                    addressLine2 = null,
                    city = order.ReceiverCity,
                    country = order.ReceiverCountryCode,
                    custom_ref = order.SystemNo,
                    description = order.CustomerOrderNo,
                    email = order.ReceiverEmail,
                    phone = order.ReceiverPhone,
                    postcode = order.ReceiverZipCode,
                    recipientCompany = order.ReceiverCompany,
                    recipientName = order.ReceiverName,
                    state = order.ReceiverState,
                    weight = order.CustomerWeight.KGFormat()
                }
                }
            };

            return orderParam;
        }
        private T SendPost<T>(Logistics_Channel channel, string uri, object param) where T : new()
        {
            //channel.ApiKey = "Y2SDXOG3ICJ1U0Q9R74BFOHJQGAI24FT";
            //channel.ApiSecret = "RP2KR6OKTQH8L71VG63G5NROHL2BK48Z";
            string host = channel.ApiHost;
            string key = channel.ApiKey;
            string token = channel.ApiSecret;
            string auth = GenAuth(token, key, uri, out string date);

            RestSharp.RestClient client = new RestSharp.RestClient(host);
            RestSharp.RestRequest req = new RestSharp.RestRequest(uri, RestSharp.Method.POST);
            req.AddHeader("Content-Type", "application/json");
            req.AddHeader("Accept", "application/json");
            req.AddHeader("SHIPMENTAPI-DATE", date);
            req.AddHeader("SHIPMENTAPI-AUTH", auth);
            req.AddJsonBody(param);

            var resp = client.Execute<T>(req);
            return resp.Data;
        }
        private string GenAuth(string token, string key, string uri, out string date)
        {
            date = GetDateFormat();

            string raw = $":{date}:{uri}";
            var auth = hmacSHA1(key, raw);

            var result = $"{token}:{auth}";
            return result;
        }
        private string GetDateFormat()
        {
            string date = DateTime.Now.ToString("r");
            date = date.Replace("GMT", "+0000");
            return date;
        }
        private string hmacSHA1(string key, string message)
        {
            byte[] hashBytes;
            using (HMACSHA1 hmac = new HMACSHA1(Encoding.ASCII.GetBytes(key)))
            {
                hashBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(message));
            }

            return System.Convert.ToBase64String(hashBytes);
        }
        private UploadResult CreateUploadResult(CreateOrderResponse response)
        {
            CreateOrderResult result = response?.result?.FirstOrDefault();
            bool isSuccess = IsCreateOrderSuccess(response, out string errorMsg);
            string serviceOrderNum = isSuccess ? result?.id : string.Empty;
            string trackingNum = isSuccess ? result?.tracking : string.Empty;
            UploadResult uploadResult = new UploadResult
            {
                Error = errorMsg,
                IsSuccess = isSuccess,
                ResponseContent = errorMsg,
                ServiceOrderNumber = serviceOrderNum,
                TrackingNumber = trackingNum,
            };
            return uploadResult;

        }
        private bool IsCreateOrderSuccess(CreateOrderResponse response, out string errorMsg)
        {
            var result = response?.result?.FirstOrDefault();
            if (result == null)
            {
                if (!string.IsNullOrEmpty(response.error) || !string.IsNullOrEmpty(response.additional_info) || !string.IsNullOrEmpty(response.Message))
                {
                    errorMsg = $"{response.error} {response.additional_info} {response.Message}";
                    return false;
                }

                errorMsg = "创建订单返回结果不能为空";
                return false;
            }

            bool isSuccess = string.IsNullOrEmpty(result.error);
            if (isSuccess)
            {
                errorMsg = string.Empty;
                return true;
            }
            else
            {
                string msg = result.error;
                errorMsg = $"下单接口返回错误:{msg} {result.additional_info} {result.code}";
            };
            return isSuccess;
        }
        private byte[] DownPdf(Logistics_Channel channel, string uri, object param)
        {
            //channel.ApiKey = "Y2SDXOG3ICJ1U0Q9R74BFOHJQGAI24FT";
            //channel.ApiSecret = "RP2KR6OKTQH8L71VG63G5NROHL2BK48Z";
            string host = channel.ApiHost;
            string key = channel.ApiKey;
            string token = channel.ApiSecret;
            string auth = GenAuth(token, key, uri, out string date);

            RestSharp.RestClient client = new RestSharp.RestClient(host);
            RestSharp.RestRequest req = new RestSharp.RestRequest(uri, RestSharp.Method.POST);
            req.AddHeader("Content-Type", "application/json");
            req.AddHeader("Accept", "application/json");
            req.AddHeader("SHIPMENTAPI-DATE", date);
            req.AddHeader("SHIPMENTAPI-AUTH", auth);
            req.AddJsonBody(param);

            var resp = client.DownloadData(req);
            return resp;
        }
        #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)
        {
            string uri = "/app/services/multicourier/createorder";
            OrderModelJudge(order);

            var param = CreateOrderRequestParam(order);
            var resp = SendPost<CreateOrderResponse>(channel, uri, param);
            var result = CreateUploadResult(resp);
            if (!result.IsSuccess)
            {
                if (result.Error.Contains("Delivery city/suburb do not match the postcode "))
                {
                    //如果发货地区、邮编、州、城市对应不上
                    var list = _orderPrintQtyRepository.FindAUArea(order.ReceiverZipCode, order.ReceiverState);
                    var item = list.FirstOrDefault(x => order.ReceiverStreet.ToUpper().Contains(x));
                    if (item != null)
                    {
                        order.ReceiverCity = item;
                        param = CreateOrderRequestParam(order);
                        resp = SendPost<CreateOrderResponse>(channel, uri, param);
                        result = CreateUploadResult(resp);
                    }
                    else
                    {
                        if (order.CustomerId == 7 && !arg.asTransfer)
                        {
                            throw new Exception("客户不使用澳邮偏远服务");
                        }
                        else
                        {
                            throw new Exception("城市与邮编校验失败，请参阅 https://auspost.com.au/postcode 进行相关的地址修改");
                        }
                    }
                }
            }
         
            if (result.TrackingNumber.Contains("WJY")
                && (new int[] { 1, 281, 7, 193, 360 }).Contains(order.CustomerId))
            {
                throw new Exception("澳邮客户偏远直接退回");
            }
            return result;
        }

        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            PrintLabelParam param = new PrintLabelParam
            {
                ids = new List<string> { result.ServiceOrderNumber },
                printType = "auspost",
                returnType = "pdf"
            };

            string uri = "/app/services/multicourier/printlabel";

            byte[] pdfData = null;
            string lastErrorMessage = string.Empty;
            for (int i = 0; i < 5; i++)
            {
                try
                {
                    pdfData = DownPdf(channel, uri, param);
                    if (pdfData != null && pdfData.Length > 10000)
                    {
                        break;
                    }
                    System.Threading.Thread.Sleep(1000);
                }
                catch (Exception ex)
                {
                    lastErrorMessage = ex.Message;
                }
            }

            if (pdfData.Length < 5000)
            {
                throw new Exception("面单下载失败，请稍候重试");
            }
            return pdfData;
        }

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