using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using XYY.Core.Standard.Data.Infrastructure;
using XYY.Core.Standard.ExtendMethods;
using XYY.Data.Standard.Order;
using XYY.Model.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.Base;

namespace XYY.Service.Standard.ChannelApi.AGS
{
    internal partial class Api : IBaseApi
    {
        public string ServiceName => "AGS";
        readonly IOrderRepository _orderRepository;
        readonly IOrderGoodsRepository _goodsRepository;

        static Dictionary<string, string> enNameMapping = new Dictionary<string, string>
        {
            {"shoes","Women's flat shoes"},
            {"bag","Casual handbag"},
            {"bags","Casual handbag"},
        };

        public Api(IOrderRepository orderRepository, IOrderGoodsRepository goodsRepository)
        {
            _orderRepository = orderRepository;
            _goodsRepository = goodsRepository;
        }

        public async Task<List<BagDeclareErrosResult>> BagDeclare(BagDeclareRequest bagDeclareRequest)
        {
            //bagDeclareRequest.Channel.ApiHost = "http://rps.sandbox.miqexpress.com";
            //bagDeclareRequest.Channel.ApiKey = "7832e4-8862c9-3e3df5-f0c107-95cec6";
            List<BagDeclareErrosResult> bagDeclareErrosResults = new List<BagDeclareErrosResult>();
            var list = new List<BoxDetailItem>(bagDeclareRequest.BatchDeclare.SelectMany(x => x.Value));
            var g = list.GroupBy(x => new { x.LadingBillNumber, x.Port });
            foreach (var item in g)
            {

                ManifestRequest request = new ManifestRequest
                {
                    customerReference1 = item.Key.LadingBillNumber,
                    description = DateTime.Now.ToString_yyyyMMddHHmm(),
                    portOfEntry = item.Key.Port,
                    receptacleList = new List<ReceptacleListItem>()
                };

                request.parcelList = item.Select(x => new ParcelList
                {
                    height = 1,
                    width = 7,
                    length = 10,
                    dimensionUom = "CM",
                    trackingNumber = x.TrackingNumber,
                    weight = x.Weight / 1000.0d,
                    weightUom = "KG",
                    receptacleId = x.BoxNumber,
                    commodityForms = x.TrackingNumber == "4013111019187469" 
                    || x.TrackingNumber == "4013111019187476" 
                    || x.TrackingNumber == "4013111019187490" 
                    || x.TrackingNumber == "4013111019187544" ? DeclareGoods(x.Weight, x.TrackingNumber) : null
                }).ToList();


                RestSharp.RestClient client = new RestSharp.RestClient(bagDeclareRequest.Channel.ApiHost);
                RestSharp.RestRequest restRequest = new RestSharp.RestRequest("rps-api/manifest/submit", RestSharp.Method.POST);
                restRequest.AddHeader("api-key", bagDeclareRequest.Channel.ApiKey);
                restRequest.AddJsonBody(request);
                string json = Newtonsoft.Json.JsonConvert.SerializeObject(request);
                var restResult = client.Execute(restRequest);
                if (restResult.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    var r = Newtonsoft.Json.JsonConvert.DeserializeObject<ManifestResult>(restResult.Content);
                    if (r.code == 200) 
                    {
                        bagDeclareErrosResults.AddRange(r.payload.failList.Where(x => x.errorMessage != "Already submitted")
                            .Select(x => new BagDeclareErrosResult
                            {
                                ErrorMessage = x.errorMessage,
                                TrackingNumber = x.trackingNumber,
                            }).ToList());
                    }
                    else
                    {
                        bagDeclareErrosResults.AddRange(item.Select(x => new BagDeclareErrosResult
                        {
                            TrackingNumber = x.TrackingNumber,
                            ErrorMessage = r.message
                        }).ToList());
                    }
                }
                else
                {
                    bagDeclareErrosResults.AddRange(item.Select(x => new BagDeclareErrosResult
                    {
                        TrackingNumber = x.TrackingNumber,
                        ErrorMessage = restResult.Content ?? restResult.ErrorMessage
                    }).ToList());
                }
            }
            return bagDeclareErrosResults;
        }
        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 Exception();
        }

        //public string[] ToArray(string str, int maxLength)
        //{
        //    string[] arr = str.Split(' ', '.');
        //    int page = ((str.Length + maxLength) - 1) / maxLength;
        //    string[] addressArr = new string[page];

        //    int flag = 0;
        //    int t = arr.Count();
        //    for (int i = 0; i < page; i++)
        //    {
        //        string temp = "";
        //        for (int j = 0; j < t; j++)
        //        {
        //            if ((temp += arr[flag] + " ").Length <= maxLength)
        //            {
        //                addressArr[i] += arr[flag] + " ";
        //                flag++;
        //            }
        //        }
        //        t = arr.Count() - flag;
        //    }
        //    return addressArr;
        //}

        public static string ExtractNumber(string phoneString)
        {
            string phones = "";
            MatchCollection result = Regex.Matches(phoneString, @"[\d]+");
            for (int i = 0; i < result.Count; i++)
            {
                phones += result[i].Value;
            }
            return phones;
        }

        private List<commodityForms> DeclareGoods(int weight, string trackingNumber)
        {
            var goods = (_goodsRepository
                .QueryBySqlAsync("select b.* from order_order(nolock)a join order_orderGoods(nolock)b on a.id=b.orderId where a.trackingNumber = @trackingNumber"
                , new { trackingNumber = trackingNumber }).Result).ToList();

            if (goods.Any(x => x.Weight == 0))
            {
                //平摊物品重量
                int goodsQty = goods.Sum(x => x.Quantity);
                decimal avgWeight = Math.Floor(weight / (decimal)goodsQty);
                goods.ForEach(x => x.Weight = (int)avgWeight);

                goods.ForEach(item =>
                {
                    if (item.DeclareCurrency == "USD")
                    {
                        item.DeclareCurrency = "CAD";
                        item.DeclareFee = item.DeclareFee * 1.2911m;
                    }
                    else if (item.DeclareCurrency == "EUR")
                    {
                        item.DeclareCurrency = "CAD";
                        item.DeclareFee = item.DeclareFee * 1.2911m;

                    }
                });
            }

            List<commodityForms> commodityForms = new List<commodityForms>();
            foreach (var x in goods)
            {
                string enName = x.EnName.Trim();
                if (!enName.Contains(" "))
                {
                    foreach (var dic in enNameMapping)
                    {
                        if (dic.Key.Contains(enName, StringComparison.OrdinalIgnoreCase))
                        {
                            enName = dic.Value;
                        }
                    }
                }
                var g = new commodityForms
                {
                    name = enName,
                    country = "CN",
                    currency = x.DeclareCurrency,
                    description = x.EnName,
                    hsCode = x.HsCode,
                    units = x.Quantity,
                    unitValue = Math.Round(x.DeclareFee, 2),
                    unitWeight = x.Weight / 1000.0
                };
                commodityForms.Add(g);
            }
            //List<commodityForms> commodityForms = goods.Select().ToList();
            return commodityForms;


        }

        public async Task<UploadResult> DataUpload(Order_Order order, List<Order_OrderGoods> goods, Logistics_Channel channel, ExtendArg arg)
        {
            //channel.ApiHost = "http://rps.sandbox.miqexpress.com";
            //channel.ApiKey = "7832e4-8862c9-3e3df5-f0c107-95cec6";
            string port = null;
            if (order.ChannelId == 371)
            {
                if (!string.IsNullOrEmpty(order.ReceiverZipCode))
                {
                    string YYZList = "A/B/C/E/G/H/J/K/L/M/N/P";
                    string YVRList = "R/S/T/V/X/Y";
                    string zipStart = order.ReceiverZipCode.Substring(0, 1);
                    if (YYZList.Contains(zipStart, StringComparison.InvariantCultureIgnoreCase))
                    {
                        port = "YYZ";
                    }
                    else if (YVRList.Contains(zipStart, StringComparison.InvariantCultureIgnoreCase))
                    {
                        port = "YVR";
                    }
                }
            }
            string[] receiveryAddress = order.ReceiverStreet.Replace("|", "").ToArray(40);
            if (receiveryAddress.Length > 2)
                throw new Exception("地址超长");


            if (goods.Any(x => x.Weight == 0))
            {
                //平摊物品重量
                int goodsQty = goods.Sum(x => x.Quantity);
                decimal avgWeight = Math.Floor(order.CustomerWeight / (decimal)goodsQty);
                goods.ForEach(x => x.Weight = (int)avgWeight);
            }

            string code = "";
            order.ReceiverState = order.ReceiverState.Replace("CA-", "");
            order.ReceiverState = order.ReceiverState.Replace("B.C.", "BC");
            order.ReceiverState = order.ReceiverState.Replace("B.C", "BC");
            order.ReceiverState = order.ReceiverState.Replace("B C", "BC");
            if (!string.IsNullOrEmpty(order.ReceiverState))
            {
                switch (order.ReceiverState.ToLower())
                {
                    case "ontario":
                        code = "ON";
                        break;
                    case "québec":
                    case "quebec":
                        code = "QC";
                        break;
                    case "nova scotia":
                        code = "NS";
                        break;
                    case "new brunswick":
                        code = "NB";
                        break;
                    case "manitoba":
                        code = "MB";
                        break;
                    case "british columbia":
                        code = "BC";
                        break;
                    case "prince edward island":
                        code = "PE";
                        break;
                    case "alberta":
                        code = "AB";
                        break;
                    case "saskatchewan":
                        code = "SK";
                        break;
                    case "newfoundland and labrador":
                    case "newfoundland":
                        code = "NL";
                        break;
                    case "northwest territories":
                        code = "NT";
                        break;
                    case "tukon territory":
                        code = "YT";
                        break;
                    case "nunavut":
                        code = "NU";
                        break;
                }
                if (!string.IsNullOrEmpty(code))
                {
                    order.ReceiverState = code;
                }

                if (order.ReceiverState.Length != 2)
                {
                    throw new Exception("必须传入完整的州名或简码");
                }
            }

            if (!string.IsNullOrEmpty(order.ReceiverPhone))
            {
                order.ReceiverPhone = ExtractNumber(order.ReceiverPhone);
                if (string.IsNullOrEmpty(order.ReceiverPhone) || order.ReceiverPhone.Length != 10)
                {
                    if (order.ReceiverPhone.Length == 12 && order.ReceiverPhone.StartsWith("+1"))
                    {
                        order.ReceiverPhone = order.ReceiverPhone.Substring(2);
                    }
                    else if (order.ReceiverPhone.Length == 11 && order.ReceiverPhone.StartsWith("1"))
                    {
                        order.ReceiverPhone = order.ReceiverPhone.Substring(1);
                    }
                    else
                    {
                        throw new Exception("客户电话必须为10位，请不要包含国际电话区号+1 1");
                    }
                }
            }
            if (!string.IsNullOrEmpty(order.ReceiverZipCode))
            {
                order.ReceiverZipCode = order.ReceiverZipCode.Replace(" ", "").ToUpper();
            }

            foreach (var item in goods)
            {
                if (item.DeclareCurrency == "USD")
                {
                    item.DeclareCurrency = "CAD";
                    item.DeclareFee = item.DeclareFee * 1.2911m;
                }
                else if (item.DeclareCurrency == "EUR")
                {
                    item.DeclareCurrency = "CAD";
                    item.DeclareFee = item.DeclareFee * 1.2911m;

                }
            }
            string customerRefNum = order.SystemNo;

            if (order.CustomerId == 676)
            {
                customerRefNum = order.CustomerOrderNo;
            }

            string resendOldTrackingNum = null;
            if (order.IsResend)
            {
                if (order.CustomerOrderNo.StartsWith("cp"))
                {
                    var oldCustomerRefNum = order.CustomerOrderNo.Substring(2);
                    var oldOrders = await _orderRepository.QueryAsync(i => i.CustomerOrderNo == oldCustomerRefNum);
                    if (oldOrders?.Any() != true)
                    {
                        throw new Exception($"重派时找不到原订单信息,CustomerOrderNo={oldCustomerRefNum}");
                    }
                    else
                    {
                        var oldOrder = oldOrders.First();
                        resendOldTrackingNum = oldOrder.TrackingNumber;
                    }
                }
                else
                {
                    throw new Exception("新的重派单号格式为\"cp\"加原客户单号");
                }
            }
            string remark2 = order.SystemNo;
            if (order.CustomerId == 353)
            {
                remark2 = order.CustomerOrderNo;
            }
            OrderRequest request = new OrderRequest
            {
                courierCode = "AGS_GSCP",
                portOfEntry = port,
                weight = order.CustomerWeight,
                weightUom = "G",
                dimensionUom = "CM",
                height = 1,
                width = 7,
                length = 10,
                customerRefId = customerRefNum,
                parcelType = "Bag",
                signature = false,
                deliveryOption = "no_delivery_option_selected",
                commodityForms = goods.Select(x => new CommodityFormsItem
                {
                    name = x.EnName,
                    country = "CN",
                    currency = x.DeclareCurrency,
                    description = x.EnName,
                    hsCode = x.HsCode,
                    units = x.Quantity,
                    unitValue = Math.Round(x.DeclareFee, 2),
                    unitWeight = x.Weight
                }).ToList(),



                customizedInfoForm = new CustomizedInfoForm
                {
                    remark1 = (order.IsResend && !string.IsNullOrEmpty(resendOldTrackingNum)) ? resendOldTrackingNum : port,
                    remark2 = remark2
                },
                recipient = new Recipient
                {
                    recipientName = order.ReceiverName,
                    recipientAddress1 = receiveryAddress[0],
                    recipientAddress2 = receiveryAddress.Length > 1 ? receiveryAddress[1] : "",
                    recipientCity = order.ReceiverCity,
                    recipientState = order.ReceiverState,
                    recipientZip5 = order.ReceiverZipCode,
                    recipientCountry = order.ReceiverCountryCode,
                    recipientPhone = order.ReceiverPhone,
                    recipientEmail = order.ReceiverEmail
                },
                validateAddress = true,
            };

            if (!order.IsResend)
            {
                request.customerRefId = request.customerRefId + "R3";
            }

            RestSharp.RestClient client = new RestSharp.RestClient(channel.ApiHost);
            RestSharp.RestRequest restRequest = new RestSharp.RestRequest("rps-api/label/create-label", RestSharp.Method.POST);
            restRequest.AddHeader("api-key", channel.ApiKey);
            restRequest.AddJsonBody(request);

            var restResult = client.Execute(restRequest);
            if (restResult.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var r = Newtonsoft.Json.JsonConvert.DeserializeObject<OrderResult>(restResult.Content);
                if (!string.IsNullOrEmpty(r.message) && r.message.Contains("Carrier: duplicate_reference_number"))
                {
                    var tracking = await _orderRepository.GetChannelOrderInfoRecord(order.ChannelId, order.SystemNo);
                    if (string.IsNullOrEmpty(tracking))
                    {
                        throw new Exception("对方提示重复，但是找不到已下单信息");
                        //RestSharp.RestClient fclient = new RestSharp.RestClient(channel.ApiHost);
                        //RestSharp.RestRequest frestRequest = new RestSharp.RestRequest("/rps-api/label/void-label-by-customer-ref-id", RestSharp.Method.POST);
                        //frestRequest.AddHeader("api-key", channel.ApiKey);
                        //frestRequest.AddQueryParameter("customerRefId", request.customerRefId);
                        //var fReseponse = fclient.Execute(frestRequest);
                        //if (fReseponse.StatusCode == System.Net.HttpStatusCode.OK)
                        //{
                        //    var r4 = Newtonsoft.Json.JsonConvert.DeserializeObject<OrderResult>(fReseponse.Content);
                        //    tracking = r4.payload.trackingNumber;
                        //}
                        //else
                        //{
                        //    throw new Exception("查找已下单信息失败:" + (fReseponse.Content ?? fReseponse.ErrorMessage));
                        //}
                    }
                    string tr = $"/rps-api/label/get-label-base64/pdf/{tracking}";
                    restRequest = new RestSharp.RestRequest(tr, RestSharp.Method.GET);
                    restRequest.AddHeader("api-key", channel.ApiKey);
                    var r2 = client.Execute(restRequest);
                    if (r2.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        var r3 = Newtonsoft.Json.JsonConvert.DeserializeObject<OrderResult>(r2.Content);
                        return new UploadResult
                        {
                            DownloadUrl = r3.payload.labelBase64,
                            IsSuccess = true,
                            destinationCode = port,
                            TrackingNumber = tracking
                        };
                    }
                    else
                    {
                        throw new Exception("获取面单信息失败:" + r2.Content ?? r2.ErrorMessage);
                    }

                }
                else if (!string.IsNullOrEmpty(r.message) && r.message.Contains("The postcode is invalid"))
                {
                    throw new Exception("收件人邮编不存在");
                }
                else if (!string.IsNullOrEmpty(r.message) && r.message.Contains("The receiver postcode and state and city not match"))
                {
                    throw new Exception($"收件人邮编存在但和城市不符：{r.message}");
                }
                if (r.code == 200)
                {
                    await _orderRepository.AddChannelOrderInfoRecord(order.ChannelId, r.payload.trackingNumber, order.SystemNo);
                    return new UploadResult
                    {
                        DownloadUrl = r.payload.labelBase64,
                        IsSuccess = true,
                        TrackingNumber = r.payload.trackingNumber,
                        destinationCode = r.payload.portOfEntry
                    };
                }
                else
                {
                    throw new Exception(r.message);
                }
            }
            else
            {
                throw new Exception(restResult.Content ?? restResult.ErrorMessage);
            }

        }
        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            return Convert.FromBase64String(result.DownloadUrl);
        }

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