using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XYY.Core.Standard.Data.Infrastructure;
using Dapper;
using XYY.Model.Standard.Channel;
using XYY.Service.Standard.Channel;
using XYY.Model.Standard.Order;
using XYY.Service.Standard.ChannelApi.Itdida;
using XYY.Data.Standard.Order;
using NPOI.POIFS.Macros;
using System.Threading.Channels;
using static XYY.Service.Standard.ChannelApi.HangLe.Api;
using System.ServiceModel.Channels;
using IoC;
using XYY.Data.Model.Standard.Tracking;

namespace XYY.Service.Standard.Order
{
    public interface IBoxService
    {
        Task<Logistics_BoxOutBatch> Scan(string BoxNumber, string channelName);

        Task<Logistics_BoxOutBatch> CanScan(string BoxNumber);

        Task EndScan();

        Task<Logistics_BoxOutBatch> GetLastScanBatch();
        Task<Logistics_Box> GetBox(string BoxNumber);
        Task SetYPDJ(BZBBoxInfo boxInfo);
    }

    public class BZBBoxInfo
    {
        public int BoxId
        {
            get; set;
        }

        public List<BoxGoodsInfoItem> ReplaterGoodsInfo
        {
            get; set;
        }
    }

    public class BoxGoodsInfoItem
    {
        public string OriCnName
        {
            get; set;
        }

        public string CnName
        {
            get; set;
        }

        public string EnName
        {
            get; set;
        }

        public string HsCode
        {
            get; set;
        }
    }


    public class BoxService : IBoxService
    {
        IUnitOfWork _unitOfWork;
        Microsoft.Extensions.Caching.Distributed.IDistributedCache _distributedCache;
        IOrderRepository _orderRepository;
        public BoxService(IUnitOfWork unitOfWork, IOrderRepository orderRepository, Microsoft.Extensions.Caching.Distributed.IDistributedCache distributedCache)
        {
            _unitOfWork = unitOfWork;
            _orderRepository = orderRepository;
            _distributedCache = distributedCache;
        }

        public async Task<Logistics_Box> GetBox(string BoxNumber)
        {
            return (await _unitOfWork.QueryAsync<Logistics_Box>(x => x.BoxNumber == BoxNumber)).FirstOrDefault();
        }

        public async Task SetYPDJ(BZBBoxInfo boxInfo)
        {
            string sql = $@"select b.* from Order_Order(nolock) a
                                join Order_OrderGoods(nolock)b on a.id=b.OrderId
                                join Logistics_BoxDetail(nolock)c on c.OrderId=b.OrderId
                                join Logistics_Box(nolock)d on d.id=c.BoxId and IsDelete=0
                                where d.Id = {boxInfo.BoxId}";
            var list = (await _unitOfWork.QueryBySqlAsync<Order_OrderGoods>(sql)).ToList();
            string orderSql = $@"select a.* from Order_Order(nolock) a 
                                join Logistics_BoxDetail(nolock)c on c.OrderId=a.id
                                join Logistics_Box(nolock)d on d.id=c.BoxId and IsDelete=0
                                where d.Id = {boxInfo.BoxId}";
            var orders = (await _unitOfWork.QueryBySqlAsync<Order_Order>(orderSql)).ToList();
            var box = (await _unitOfWork.GetAsync<Logistics_Box>(boxInfo.BoxId));
            if (!box.IsDelivery)
            {
                throw new Exception("必须封箱后才可以提交包中包订单");
            }
            if (orders.Any(x => x.ReceiverCountryCode != "US"))
                throw new Exception($"箱内订单收件人国家必须都为US");
            if (box == null)
                throw new Exception($"未找到箱子{boxInfo.BoxId}");
            List<Order_OrderGoods> goods = new List<Order_OrderGoods>();
            decimal g = list.Sum(x => x.DeclareFee * x.Quantity) / list.Sum(x => x.Quantity);

            //先替换
            foreach (var item in list)
            {
                var re = boxInfo.ReplaterGoodsInfo.FirstOrDefault(x => x.OriCnName.Trim() == item.CnName.Trim());
                if (re == null)
                {
                    throw new Exception($"未找到中文品名{item.CnName}的可替换信息");
                }
                else
                {
                    item.CnName = re.CnName;
                    item.EnName = re.EnName;
                    item.HsCode = re.HsCode;
                }
            }

            Dictionary<string, decimal> avgDeclareVal = list.GroupBy(x => x.CnName)
                .ToDictionary(x => x.Key, x => Math.Floor(x.Sum(y => y.Quantity * y.DeclareFee) / x.Sum(y => y.Quantity) * 100m) / 100m);

            //后合并
            foreach (var item in list)
            {
                var findGoods = goods.FirstOrDefault(x => x.CnName == item.CnName);
                if (findGoods == null)
                {
                    goods.Add(new Order_OrderGoods
                    {
                        CnName = item.CnName,
                        EnName = item.EnName,
                        DeclareCurrency = item.DeclareCurrency,
                        DeclareFee = avgDeclareVal[item.CnName],
                        HsCode = item.HsCode,
                        Quantity = item.Quantity
                    });
                }
                else
                {
                    findGoods.Quantity += item.Quantity;
                }
            }
            Guid guid = Guid.NewGuid();
            List<Order_ApiDeclaration> order_ApiDeclarations = goods.Select(x => new Order_ApiDeclaration
            {
                GoodsId = x.Id,
                OriginDeclareFee = x.DeclareFee,
                ChannelId = 370,
                CnName = x.CnName,
                EnName = x.EnName,
                Qty = x.Quantity,
                DeclareValue = x.DeclareFee,
                Guid = guid.ToString(),
                OrderDeclareValue = goods.Sum(x => x.Quantity * x.DeclareFee),
                SystemNo = box.BoxNumber,
                CreateTime = DateTime.Now
            }).ToList();

            await _unitOfWork.BulkToDBAsync(order_ApiDeclarations);

            Order_Order order = new Order_Order
            {
                ChannelId = 370,
                CustomerWeight = orders.Sum(x => x.OPWeight),
                ReceiverName = "SINO-US INTERNATIONAL ATTN. LOUIS LIN",
                ReceiverPhone = "6263403789",
                ReceiverCountryCode = "US",
                ReceiverState = "CA",
                ReceiverCity = "Hawthorne",
                ReceiverStreet = "12911 Simms Ave.",
                ReceiverZipCode = "90250",
                CreateOrderChannelId = 0,
                CustomerId = 0,
                SystemNo = box.BoxNumber

            };
            if (order.CustomerWeight < 21000 || order.CustomerWeight > 30000)
                throw new Exception($"包中包重量范围为(21-30)KG");

            var channel = await _unitOfWork.GetAsync<Logistics_Channel>(370);

            ItdidaApi api = new ItdidaApi(_orderRepository, _distributedCache);
            var result = await api.DataUpload(order, goods, channel, null);
            if (!result.IsSuccess)
            {
                throw new Exception(result.Error);
            }
            else
            {
                await _unitOfWork.UpdateByConditionAsync<Logistics_Box, bool>(x => x.Id == boxInfo.BoxId, new
                {
                    UserBoxNumber = result.TrackingNumber
                });
            }
        }


        public async Task<Logistics_BoxOutBatch> CanScan(string BoxNumber)
        {
            if (string.IsNullOrEmpty(BoxNumber))
                throw new Exception("未传入箱号");
            var detail = (await _unitOfWork.QueryAsync<Logistics_BoxOutBatchDetail>(x => x.BoxNumber == BoxNumber && x.IsDelete == false)).FirstOrDefault();
            if (detail == null)
                throw new Exception($"找不到待删除的箱子{BoxNumber}");
            else
            {
                detail.IsDelete = true;
                await _unitOfWork.UpdateAsync(detail);
                var batch = (await _unitOfWork.QueryAsync<Logistics_BoxOutBatch>(x => x.Id == detail.OutBatchId)).FirstOrDefault();
                //if (!batch.IsEnd)
                //    throw new Exception("批次未完成出库");
                if (batch == null)
                    throw new Exception("批次" + detail.OutBatchId + "不存在由系统内");
                else
                {
                    batch.BoxQty--;
                    await _unitOfWork.UpdateAsync(batch);
                    return batch;
                }
            }

        }

        public async Task<Logistics_BoxOutBatch> Scan(string BoxNumber, string channelName)
        {
            var channels = await ChannelClientService.CacheGetAllChannel();
            var publics = await ChannelClientService.CacheGetAllPublic();
            if (!string.IsNullOrEmpty(BoxNumber))
                BoxNumber = BoxNumber.Trim();
            var box = (await _unitOfWork.QueryAsync<Logistics_Box>(x => x.BoxNumber == BoxNumber || x.UserBoxNumber == BoxNumber)).FirstOrDefault();
            if (box == null)
                throw new Exception($"未找到相关的箱号{box.BoxNumber}的箱子");
            if (box.IsDelete)
                throw new Exception($"箱号{box.BoxNumber}已被删除，请复核");
            if (!box.IsDelivery)
                throw new Exception($"箱号{box.BoxNumber}未封箱，请复核");

            if (await _unitOfWork.IsExistsAsync<Logistics_BoxOutBatchDetail>(x => x.BoxNumber == BoxNumber && x.IsDelete == false))
            {
                throw new Exception($"{BoxNumber}已扫描出库，勿须重新出库");
            }

            //查找箱号 
            var channel = channels.FirstOrDefault(x => x.Id == box.ChannelId);
            var publicChannel = channels.FirstOrDefault(x => x.Id == channel.PublicChanneId);
            var publicc = publics.FirstOrDefault(x => x.Code == publicChannel.PublicCode);
            string date = DateTime.Now.ToString("yyyyMMdd");
            var lastNo = (await _unitOfWork.QueryAsync<Logistics_BoxOutBatch>(x => !x.IsEnd && x.Date == date)).FirstOrDefault();
            if (lastNo == null)
            {
                //如果为空新增一个批号
                var maxNo =
                    (await _unitOfWork.Connection.ExecuteScalarAsync<int>($"select max(No) from Logistics_BoxOutBatch(nolock) where Date='{date}'",
                    null, _unitOfWork.Transaction));
                int newNo = maxNo + 1;
                lastNo = new Logistics_BoxOutBatch
                {
                    No = newNo,
                    Date = date,
                    IsEnd = false,
                    Number = date + newNo.ToString("00000"),
                    ChannelId = publicChannel.Id
                };
                lastNo.Id = (int)(await _unitOfWork.InsertAsync(lastNo));
            }


            if (!string.IsNullOrEmpty(channelName))
            {
                if (publicc.Name != channelName)
                {
                    string boxChannel = channels.FirstOrDefault(x => x.Id == box.ChannelId)?.PublicName;
                    throw new Exception($"渠道不符，检验渠道为{channelName}，箱子渠道为{publicc.Name}");
                }
            }

            //增加数量
            lastNo.BoxQty += 1;
            Logistics_BoxOutBatchDetail detail = new Logistics_BoxOutBatchDetail
            {
                BoxNumber = BoxNumber,
                OutBatchId = lastNo.Id
            };
            DateTime outTime = DateTime.Now;
            //增加出库轨迹
            if (channelName == "美国快线")
            {
                //查询订单列表
                var ordsers = await _unitOfWork.QueryBySqlAsync<Order_Order>($@"
                    select a.CustomerOrderNo,a.TransferNumber,a.Id from order_order(nolock)a 
                        join Logistics_BoxDetail(nolock)b on a.id=b.orderid 
                        join Logistics_Box(nolock)c on c.id=b.boxid
                    where c.boxNumber='{BoxNumber}' and a.CustomerId in (7,691)");
                SendXiKeLogsApi(ordsers.Select(x => new
                {
                    CustomerNo = x.CustomerOrderNo,
                    TrackingEventType = TrackingEventType.OutStock,
                    Key = x.CustomerOrderNo + "_" + TrackingEventType.OutStock,
                    EventLoaction = "guangzhou",
                    EventContent = "Item outbound in sorting center.",
                    EventTime = outTime,
                    GetTime = DateTime.Now.ToString_yyyyMMddHHmmss()
                }).ToList());

                //TODO
                //物流跟踪

                //更新发货
                await _unitOfWork.ExecuteAsync(@"update a set OrderStatus=3,SendOutTime=@outTime  from order_order(nolock) a
                        join logistics_boxDetail(nolock)b on a.Id=b.OrderId  
                        join logistics_box(nolock)c on b.BoxId=c.Id  where boxNumber=@boxNumber",
                        new { outTime = outTime, boxNumber = BoxNumber });
                var logs = ordsers.Select(x => new Logistics_TrackingLog
                {
                    Location = "广州",
                    OrderId = x.Id,
                    TransferNumber = x.TransferNumber,
                    TriggerTime = outTime,
                    StatusString = "发货",
                    Status = 4,
                    Remark = "",
                    CreateTime = DateTime.Now,
                    CreateUserName = "admin"

                }).ToList();

                await _unitOfWork.BulkToDBAsync<Logistics_TrackingLog>(logs);
            }
            await _unitOfWork.InsertAsync(detail);
            await _unitOfWork.UpdateAsync(lastNo);
            return lastNo;
        }

        public static void SendXiKeLogsApi(dynamic dynamic)
        {
            RestSharp.RestClient rc = new RestSharp.RestClient("http://120.24.149.148:9520");
            RestSharp.RestRequest rq = new RestSharp.RestRequest("/api/TrackingLog/AddLog", RestSharp.Method.POST);
            rq.AddHeader("Authorization", "token 132A7468DE079C6CEB59F383A661E612");

            if (dynamic.Count > 0)
            {
                rq.AddJsonBody(dynamic);
                //最长30秒超时
                rq.Timeout = 30 * 1000;
                var res = rc.Execute(rq);
                if (res.StatusCode == System.Net.HttpStatusCode.OK)
                {

                }
                else
                {
                    throw new Exception(res.ErrorMessage ?? res.Content);
                }
            }
        }

        public async Task EndScan()
        {
            string date = DateTime.Now.ToString("yyyyMMdd");
            var lastNo = (await _unitOfWork.QueryAsync<Logistics_BoxOutBatch>(x => !x.IsEnd && x.Date == date)).FirstOrDefault();
            if (lastNo == null)
                throw new Exception("当前没有未结束的批次");
            else
            {
                lastNo.IsEnd = true;
                await _unitOfWork.UpdateAsync(lastNo);
            }
        }

        public async Task<Logistics_BoxOutBatch> GetLastScanBatch()
        {
            string date = DateTime.Now.ToString("yyyyMMdd");
            var lastNo = (await _unitOfWork.QueryAsync<Logistics_BoxOutBatch>(x => !x.IsEnd && x.Date == date)).FirstOrDefault();
            if (lastNo != null && lastNo.ChannelId > 0)
            {
                var channels = await ChannelClientService.CacheGetAllChannel();
                var publics = await ChannelClientService.CacheGetAllPublic();
                var channel = channels.FirstOrDefault(x => x.Id == lastNo.ChannelId);
                var publicChannel = channels.FirstOrDefault(x => x.Id == channel.PublicChanneId);
                var publicc = publics.FirstOrDefault(x => x.Code == publicChannel.PublicCode);
                lastNo.ChannelName = publicc.Name;
            }
            return lastNo;
        }
    }
}
