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;

namespace XYY.Service.Standard.ChannelApi.PPX
{
    public class Api : IBaseApi
    {
        public string ServiceName => "PPX-FBA";

        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)
        {
            List<OrderPackInfo> orderPackInfos = new List<OrderPackInfo>();
            CreateOrderParam createOrderParams = GenCreateOrderParam(channel, order, goods, out orderPackInfos);
            RestClient client = new RestClient(channel.ApiHost);
            RestRequest request = new RestRequest("/v1/orders", Method.POST);
            request.AddJsonBody(createOrderParams);

            SetHeader(request, channel);
            var resp = await client.ExecuteAsync<CreateOrderResponse>(request);
            if (resp.StatusCode != System.Net.HttpStatusCode.OK)
            {
                string msg = resp.Content;
                throw new Exception($"下单API请求失败:{msg}");
            }
            if (resp.Data == null || resp.Data.data == null)
            {
                string msg = resp.Content;
                throw new Exception($"下单API请求失败:返回数据为空,{msg}");
            }
            if (!resp.Data.success)
            {
                string msg = resp.Content;
                throw new Exception($"下单API请求失败:返回数据为空,{msg}");
            }

            var data = resp.Data.data;
            if (string.IsNullOrWhiteSpace(data.tracking_number))
                throw new Exception($"API请求失败:返回跟踪号为空");


            var packTrackingNumbers =await GetPackNumberInfos(channel, order.TransferNumber);
            var pakTrackingNumStrs = packTrackingNumbers.Select(i=>$"{i.TransferNumber}:{i.PackTrackingNumber}");
            var trackingNums = string.Join("|", pakTrackingNumStrs);
            UploadResult uploadResult = new UploadResult
            {
                IsSuccess = true,
                TrackingNumber = data.tracking_number,
                TransferNumner = order.TransferNumber,
                ServiceOrderNumber = data.order_sn,
                ServiceOrderNumber2= trackingNums
            };
            return uploadResult;
        }

        private async Task<List<PackNumberInfo>> GetPackNumberInfos(Logistics_Channel channel, string transferNumber)
        {
            RestClient client = new RestClient(channel.ApiHost);
            RestRequest request = new RestRequest($"/v1/orders/get-tracking-number/{transferNumber}", Method.GET);
            SetHeader(request, channel);
            var resp = await client.ExecuteAsync<GetTrackingNumberResponse>(request);
            if (resp.StatusCode != System.Net.HttpStatusCode.OK)
            {
                string msg = resp.Content;
                throw new Exception($"获取箱子跟踪号失败:{msg}");
            }
            if (resp.Data == null || resp.Data.data == null || resp.Data.data.packages == null)
            {
                string msg = resp.Content;
                throw new Exception($"获取箱子跟踪号API请求失败:返回数据为空,{msg}");
            }
            if (!resp.Data.success)
            {
                string msg = resp.Content;
                throw new Exception($"获取箱子跟踪号API请求失败:返回数据为空,{msg}");
            }

            List<PackNumberInfo> result = new List<PackNumberInfo>();
            foreach (var p in resp.Data.data.packages)
            {
                result.Add(new PackNumberInfo { PackTrackingNumber = p.tracking_number, TransferNumber = p.package_number });
            }
            return result;
        }

        private void SetHeader(RestRequest request, Logistics_Channel channel)
        {
            string raw = $"{channel.ApiKey}:{channel.ApiSecret}";
            var bytes = System.Text.Encoding.UTF8.GetBytes(raw);
            string content = Convert.ToBase64String(bytes);
            request.AddHeader("Authorization", $"Basic {content}");
        }

        private CreateOrderParam GenCreateOrderParam(Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> goods, out List<OrderPackInfo> orderPackInfos)
        {
            List<Package> packages = new List<Package> { };
            List<Products> products = new List<Products>();
            orderPackInfos = new List<OrderPackInfo>();

            var goodsGroups = goods.GroupBy(g => g.OrderId);

            foreach (var g in goodsGroups)
            {
                var firstGoods = g.First();
                var infos = firstGoods.Remark.Split(":");
                var transferNumber = infos[0];
                var lengthStr = infos[1];
                var widthStr = infos[2];
                var heightStr = infos[3];
                var weightStr = infos[4];

                int.TryParse(lengthStr, out int length);
                int.TryParse(widthStr, out int width);
                int.TryParse(heightStr, out int height);
                int.TryParse(weightStr, out int weight);

                OrderPackInfo orderPackInfo = new OrderPackInfo
                {
                    Height = height,
                    Length = length,
                    TransferNumber = transferNumber,
                    Weight = weight,
                    Width = width
                };
                orderPackInfos.Add(orderPackInfo);

                int weight_g = weight <= 0 ? order.CustomerWeight : weight;
                decimal weight_kg = weight_g / 1000.0m;

                Package package = new Package
                {
                    length = length <= 0 ? order.Length : length,
                    width = width <= 0 ? order.Width : width,
                    height = height <= 0 ? order.Height : height,
                    package_number = transferNumber,
                    weight = weight_kg,
                };
                packages.Add(package);
            }

            foreach (var g in goods)
            {
                var goodsWeight_g = g.Weight;
                var goodsWeight_kg = goodsWeight_g / 1000m;
                Products p = new Products
                {
                    dec_cn_name = g.CnName,
                    dec_en_name = g.EnName,
                    dec_weight = goodsWeight_kg,
                    dec_value = g.DeclareFee,
                    hs_code = g.HsCode,
                    package_number = order.TransferNumber,
                    quantity = g.Quantity,
                    sku = g.GoodsNumber,
                };
                products.Add(p);
            }

            CreateOrderParam result = new CreateOrderParam
            {
                city = order.ReceiverCity,
                company = string.IsNullOrWhiteSpace(order.ReceiverCompany) ? "no company" : order.ReceiverCompany,
                consignee = order.ReceiverName,
                country = order.ReceiverCountryCode,
                postcode = order.ReceiverZipCode,
                province = order.ReceiverState,
                reference_no = order.TransferNumber,
                street1 = order.ReceiverStreet,
                tel = order.ReceiverPhone,
                packages = packages,
                products = products,
                sender_address_id = 150,
                shipping_code = channel.ServiceChannelCode,
                remark = "none",
                street2 = "-"
            };

            return result;
        }

        public async Task<byte[]> DrawPdfLabel(UploadResult result, Logistics_Channel channel, Order_Order order, List<Order_OrderGoods> orderGoods)
        {
            string reference_no = order.TransferNumber;
            string url = $"/v1/orders/get-label/{reference_no}";
            RestClient client = new RestClient(channel.ApiHost);
            RestRequest request = new RestRequest(url, Method.GET);
            request.AddHeader("Content-Type", "application/json");
            SetHeader(request, channel);

            var resp = await client.ExecuteAsync<GetLabelResponse>(request);
            if (resp.StatusCode != System.Net.HttpStatusCode.OK)
            {
                string msg = resp.Content;
                throw new Exception($"获取面单API请求失败:{msg}");
            }
            if (resp.Data == null || resp.Data.data == null)
            {
                string msg = resp.Content;
                throw new Exception($"获取面单API请求失败:返回数据为空,{msg}");
            }
            if (!resp.Data.success)
            {
                string msg = resp.Content;
                throw new Exception($"获取面单API请求失败:返回数据为空,{msg}");
            }

            if (string.IsNullOrWhiteSpace(resp.Data.data.label_url))
            {
                throw new Exception($"获取面单API请求失败:面单地址为空");
            }

            string labelUrl = resp.Data.data.label_url;
            RestClient client2 = new RestClient();
            RestRequest req = new RestRequest(labelUrl);

            var labelData = await Task.Run(() =>
            {
                var data = client2.DownloadData(req);
                return data;
            });
            return labelData;
        }

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

    class OrderPackInfo
    {
        public string TransferNumber { get; set; }
        public int Length { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public decimal Weight { get; set; }
    }

    class PackNumberInfo
    {
        public string TransferNumber { get; set; }
        public string PackTrackingNumber { get; set; }
    }
}
