
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XYY.Core.Standard.Data.Infrastructure;
using XYY.Service.Standard.Finance.Charging.Base;
using Dapper;
using XYY.Core.Standard.Data.Redis;
using XYY.Core.Standard.Mvc;
using System.Security.Policy;
using System.Threading;

namespace XYY.Service.Standard.Finance.Charging.Express
{

    public class ExpressFeeBaseDetail
    {
        public string FeeType
        {
            get; set;
        }

        public IEnumerable<dynamic> Data
        {
            get; set;
        }

        public long DateTimeVersion
        {
            get; set;
        }

        public ExpressFeeBaseDetail(string type, long dateTimeVersion, IEnumerable<dynamic> data)
        {
            this.FeeType = type;
            this.Data = data;
            this.DateTimeVersion = dateTimeVersion;
        }
    }

    /// <summary>
    /// 单纯运费计算
    /// </summary>
    public interface IExpressFeeChargesService : IChargesService<ExpressFeechargesModel>
    {
        Task<ApiJsonModel> LoadExpressFeeBases(int expressId = 0, int customerId = 0);
        Task<ApiJsonModel> LoadSupplement();
    }

    public class ExpressFeeChargesService : IExpressFeeChargesService
    {
        IUnitOfWork _unitOfWork;
        IDatabase db;
        IServer server;
        public ExpressFeeChargesService(RedisHelper helper, IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
            if (_unitOfWork == null)
                throw new ExpressFeeChangesException(ExpressFeeChangesException.DB_ConnectionError);
            this.db = helper.GetDatabase();
            this.server = helper.GetServer();
        }

        [NonTrans]
        /// <summary>
        /// 获取基本的计费因子配置
        /// 仅获取3个月内的计费因子
        /// </summary>
        public async Task<ApiJsonModel> LoadExpressFeeBases(int expressId = 0, int customerId = 0)
        {
            try
            {
                ThreadPool.SetMinThreads(200, 200);
                var batch = db.CreateBatch();
                #region 操作
                //if (expressId == 0 && customerId == 0)
                //{
                //    throw new Exception("不应清理所有的运费");
                //    //await db.DeleteScanKey(batch, "Fee*");
                //}
                List<Task> tasks = new List<Task>();
                Task t3 = null;
                if (expressId != 0 && customerId != 0)
                {
                    string key = $"Fee{customerId.ToString("00000")}{expressId.ToString("00000")}*";
                    t3 = db.DeleteScanKey(batch, key);
                    if (t3 != null)
                        tasks.Add(t3);
                }

                var t1 = await LoadGrads(batch, expressId, customerId);
                tasks.AddRange(t1.ToArray());
                var t2 = await LoadRanges(batch, expressId, customerId);
                tasks.AddRange(t2.ToArray());
                var t4 = await LoadRefFee(batch, expressId, customerId);
                tasks.AddRange(t4);
                batch.Execute();
                Task.WaitAll(tasks.ToArray());
                #endregion
            }
            catch (Exception ex)
            {
                throw ex;
                return ApiJsonModel.Error(ex.Message);
            }
            return ApiJsonModel.OK("成功");
        }

        public async Task<ApiJsonModel> LoadSupplement()
        {
            await LoadGradsSupplement();
            //await LoadRangesSupplement();
            return ApiJsonModel.OK();
        }

        /// <summary>
        /// 获取区间报价
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        private async Task LoadRangesSupplement()
        {
            string sql = $@"with t1 as(
                             select ROW_NUMBER()
		                            over (PARTITION BY CustomerId,ExpressId order by EnableTime desc) r,*
	                            from Logistics_ExpressFeeBase(nolock) where EnableTime<dateadd(DAY,-90,'2022-01-06 18:00:00') and EnableTime>'2020-01-01'
                             and CustomerId >0 
                             )
							      select a.CustomerId,a.EnableTime,a.ExpressId,b.Countory,b.StartWeight,b.EndWeight,b.Fee
								      from t1 a join
                                   Logistics_ExpressFeeRange(nolock)b on a.id=b.BaseId
	                                  where   b.IsDelete=0 and a.ExpressId>0  
								       and a.ExpressId   in (49)
								       and not  exists(
								       select * from (
								       select CustomerId,ExpressId  from Logistics_ExpressFeeBase(nolock) where EnableTime>=dateadd(DAY,-90,'2022-01-06 18:00:00')
								       and CustomerId>0
								       group by CustomerId,ExpressId )c where a.CustomerId=c.CustomerId and a.ExpressId=c.ExpressId )  
                                  order by a.CustomerId,a.ExpressId,b.Countory,a.EnableTime";
            var data = await _unitOfWork.Connection.QueryAsync<dynamic>(sql);
            foreach (var item in data.GroupBy(x => new { x.CustomerId, x.EnableTime, x.ExpressId, x.Countory }))
            {
                var details = item.Select(x => new { x.StartWeight, x.EndWeight, x.Fee });
                var jsonData = new ExpressFeeBaseDetail(ExpressFeeChargesType.Range,
                    int.Parse(item.Key.EnableTime.ToString("yyyyMMdd")), details);
                string jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);
                ExpressFeeBase expressFeeBase = new ExpressFeeBase(item.Key.CustomerId, item.Key.ExpressId, item.Key.Countory, item.Key.EnableTime,
                    jsonBody);
                db.SortedSetAdd(expressFeeBase.Key, jsonBody, expressFeeBase.DateTimeVersion);
            }
        }

        private async Task<List<Task>> LoadRefFee(IBatch batch, int expressId = 0, int customerId = 0)
        {
            string where = "";
            if (expressId != 0)
            {
                where += $" and a.ExpressId={expressId}";
            }
            if (customerId != 0)
            {
                where += $" and CustomerId={customerId}";
            }



            string sql = $@"select a.CustomerId,a.EnableTime,a.ExpressId,b.Countory,b.FristFee,b.FristWeight,b.ContinuedFee,b.ContinuedWeight,b.MaxWeight from Logistics_ExpressFeeBase(nolock)a join
                             Logistics_ExpressFeeGrads(nolock)b on a.BaseExpressId=b.BaseId
	                            where EnableTime > dateadd(day,-720,getdate()) and CustomerId>0  and b.IsDelete=0 and a.ExpressId>0
                                        {where}
                            order by a.CustomerId,a.ExpressId,b.Countory,a.EnableTime";
            return await LoadGrads(batch, sql);
        }


        /// <summary>
        /// 获取区间报价
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        private async Task<List<Task>> LoadRanges(IBatch batch, int expressId = 0, int customerId = 0)
        {
            string where = "";
            if (expressId != 0)
            {
                where += $" and a.ExpressId={expressId}";
            }
            if (customerId != 0)
            {
                where += $" and a.CustomerId={customerId}";
            }

            string sql = $@"
                         with t1 as(
                        select
		                        row_number() over(partition by expressid,customerid order by EnableTime desc)r,CustomerId,EnableTime,ExpressId,Id
	                        from Logistics_ExpressFeeBase(nolock)  )

	                        select a.CustomerId,a.EnableTime,a.ExpressId,b.Countory,b.StartWeight,b.EndWeight,b.Fee
		                        from t1 a join Logistics_ExpressFeeRange(nolock)b
	                        on a.Id = b.BaseId and a.r<=5
	                        where  a.CustomerId>0 and a.ExpressId>0 and b.IsDelete =0 {where}
                         order by a.CustomerId,a.ExpressId,b.Countory,a.EnableTime
                        ";
            var data = await _unitOfWork.Connection.QueryAsync<dynamic>(sql);
            Dictionary<string, Dictionary<long, string>> dicts = new Dictionary<string, Dictionary<long, string>>();
            foreach (var item in data.GroupBy(x => new { x.CustomerId, x.EnableTime, x.ExpressId, x.Countory }))
            {
                var details = item.Select(x => new { x.StartWeight, x.EndWeight, x.Fee });
                var jsonData = new ExpressFeeBaseDetail(ExpressFeeChargesType.Range,
                    int.Parse(item.Key.EnableTime.ToString("yyyyMMdd")), details);
                string jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);
                ExpressFeeBase expressFeeBase = new ExpressFeeBase(item.Key.CustomerId, item.Key.ExpressId, item.Key.Countory, item.Key.EnableTime,
                    jsonBody);
                if (!dicts.Any(x => x.Key == expressFeeBase.Key))
                {
                    dicts[expressFeeBase.Key] = new Dictionary<long, string>();
                }
                dicts[expressFeeBase.Key].Add(expressFeeBase.DateTimeVersion, jsonBody);
            }
            List<Task> tasks = new List<Task>();
            foreach (var i in dicts)
            {
                tasks.Add(batch.SortedSetAddAsync(i.Key, i.Value.Select(x => new SortedSetEntry(x.Value, x.Key)).ToArray(), StackExchange.Redis.CommandFlags.None));
            }
            return tasks;
        }


        private async Task LoadGradsSupplement()
        {
            ThreadPool.SetMinThreads(200, 200);
            string sql = $@"with t1 as(
                             select ROW_NUMBER()
		                            over (PARTITION BY CustomerId,ExpressId order by EnableTime desc) r,*
	                            from Logistics_ExpressFeeBase(nolock) where   EnableTime>='2020-01-01'
                             and CustomerId >0 
                             )
                               select a.CustomerId,a.EnableTime,a.ExpressId,b.Countory,b.FristFee,b.FristWeight,b.ContinuedFee,b.ContinuedWeight,b.MaxWeight from t1 a join
                                                         Logistics_ExpressFeeGrads(nolock)b on a.id=b.BaseId
	                                                        where  b.IsDelete=0 and a.ExpressId>0   and a.ExpressId = 17  
                            ";
            var data = await _unitOfWork.Connection.QueryAsync<dynamic>(sql);
            foreach (var item in data.GroupBy(x => new { x.CustomerId, x.EnableTime, x.ExpressId, x.Countory }))
            {
                var details = item.Select(x => new { x.FristWeight, x.FristFee, x.ContinuedWeight, x.ContinuedFee, x.MaxWeight });
                var jsonData = new ExpressFeeBaseDetail(ExpressFeeChargesType.Grads, int.Parse(item.Key.EnableTime.ToString("yyyyMMdd"))
                    , details);
                string jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);
                ExpressFeeBase expressFeeBase = new ExpressFeeBase(item.Key.CustomerId, item.Key.ExpressId, item.Key.Countory, item.Key.EnableTime,
                    jsonBody);
                db.SortedSetAdd(expressFeeBase.Key, jsonBody, expressFeeBase.DateTimeVersion);
            }
        }

        /// <summary>
        /// 获取首续重报价
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        private async Task<List<Task>> LoadGrads(IBatch batch, int expressId = 0, int customerId = 0)
        {
            string where = "";
            if (expressId != 0)
            {
                where += $" and a.ExpressId={expressId}";
            }
            if (customerId != 0)
            {
                where += $" and a.CustomerId={customerId}";
            }

            //获取最后一个首续重报价

            string sql = $@"with t1 as(
                            select
		                            row_number() over(partition by expressid,customerid order by EnableTime desc)r,CustomerId,EnableTime,ExpressId,Id
	                            from Logistics_ExpressFeeBase(nolock)  )

	                            select a.CustomerId,a.EnableTime,a.ExpressId,b.Countory,b.FristFee,b.FristWeight,b.ContinuedFee,b.ContinuedWeight,b.MaxWeight
		                            from t1 a join Logistics_ExpressFeeGrads(nolock)b
	                            on a.Id = b.BaseId and a.r<=5
	                            where a.CustomerId>0 and a.ExpressId>0 and b.IsDelete =0 {where}
                             order by a.CustomerId,a.ExpressId,b.Countory,a.EnableTime";
            return await LoadGrads(batch, sql);
        }

        private async Task<List<Task>> LoadGrads(IBatch batch, string sql)
        {
            ThreadPool.SetMinThreads(200, 200);
            var data = await _unitOfWork.Connection.QueryAsync<dynamic>(sql);
            Dictionary<string, Dictionary<long, string>> dicts = new Dictionary<string, Dictionary<long, string>>();
            foreach (var item in data.GroupBy(x => new { x.CustomerId, x.EnableTime, x.ExpressId, x.Countory }))
            {
                var details = item.Select(x => new { x.FristWeight, x.FristFee, x.ContinuedWeight, x.ContinuedFee, x.MaxWeight });
                var jsonData = new ExpressFeeBaseDetail(ExpressFeeChargesType.Grads, int.Parse(item.Key.EnableTime.ToString("yyyyMMdd"))
                    , details);
                string jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);
                ExpressFeeBase expressFeeBase = new ExpressFeeBase(item.Key.CustomerId, item.Key.ExpressId, item.Key.Countory, item.Key.EnableTime,
                    jsonBody);
                if (!dicts.Any(x => x.Key == expressFeeBase.Key))
                {
                    dicts[expressFeeBase.Key] = new Dictionary<long, string>();
                }
                dicts[expressFeeBase.Key].Add(expressFeeBase.DateTimeVersion, jsonBody);
            }
            List<Task> tasks = new List<Task>();
            foreach (var i in dicts)
            {
                tasks.Add(batch.SortedSetAddAsync(i.Key, i.Value.Select(x => new SortedSetEntry(x.Value, x.Key)).ToArray(), StackExchange.Redis.CommandFlags.None));
            }
            return tasks;
        }

        private string getZone(string stree)
        {
            //加拿大空派
            System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"[A-Z]{3}\d{1}");
            var match = regex.Match(stree);
            if (match.Success)
            {
                string v = match.Value;

                Dictionary<string, List<string>> d = new Dictionary<string, List<string>>
                {
                    {
                        "1",new List<string>{
                            "YYZ1",
                            "YYZ2",
                            "YYZ3",
                            "YYZ4",
                            "PRTO",
                            "YYZ6",
                            "YYZ7",
                            "YYZ9",
                            "YOO1",
                            "YHM1",
                            "YXX2",
                            "YOW1",
                            "YUL2",
                             "YOW3",

                    }
                    },
                    {
                        "2",new List<string>{
                            "YYC1",
                            "YEG1"
                    }
                    },
                    {
                        "3",new List<string>{
                            "YVR1",
                            "YVR2",
                            "YVR3",
                            "YVR4"
                    }
                    },
                };
                if (d.Any(x => x.Value.Contains(v)))
                {
                    var port = d.FirstOrDefault(x => x.Value.Contains(v));
                    return port.Key;
                }
            }
            return string.Empty;

        }
        private string getZoneByUSHK(string stree)//大写字母3个 数字1个
        {
            //美森卡派，海卡
            System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"[A-Z]{3}\d{1}");//大写字母3个 数字1个
            var match = regex.Match(stree);
            if (match.Success)
            {
                string v = match.Value;

                Dictionary<string, List<string>> d = new Dictionary<string, List<string>>
                {
                    {
                        "ONT8,LGB8,LAX9",new List<string>{
                            "ONT8",
                            "LGB8",
                            "LAX9",
                    }
                    },
                    {
                        "SMF3,GYR3,LAS1",new List<string>{
                            "SMF3",
                            "GYR3",
                            "LAS1",
                    }
                    },
                    {
                        "SBD1,GYR2,SCK4",new List<string>{
                            "SBD1",
                            "GYR2",
                            "SCK4",
                        }
                    },
                        {
                        "FTW1",new List<string>{
                            "FTW1",
                    }
                    },
                    //美国空卡
                    {
                        "ONT8,92551,LAX",new List<string>{
                            "ONT8",
                    }
                    },
                     {
                        "LGB8,92376,LAX",new List<string>{
                            "LGB8",
                    }
                    },
                      {
                        "LAX9,92337,LAX",new List<string>{
                            "LAX9",
                    }
                    },
                  {
                        "LAS1,89044,LAX",new List<string>{
                            "LAS1",
                    }
                },
                };
                if (d.Any(x => x.Value.Contains(v)))
                {
                    var port = d.FirstOrDefault(x => x.Value.Contains(v));
                    return port.Key;
                }
            }
            return string.Empty;
        }
        private string getZoneByUSKK(string stree)//大写字母3个 数字1个
        {
            //美国空卡
            System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"[A-Z]{3}\d{1}");//大写字母3个 数字1个
            var match = regex.Match(stree);
            if (match.Success)
            {
                string v = match.Value;

                Dictionary<string, List<string>> d = new Dictionary<string, List<string>>
                {

                    {
                        "ONT8,92551,LAX",new List<string>{
                            "ONT8",
                    }
                    },
                     {
                        "LGB8,92376,LAX",new List<string>{
                            "LGB8",
                    }
                    },
                      {
                        "LAX9,92337,LAX",new List<string>{
                            "LAX9",
                    }
                    },
                  {
                        "LAS1,89044,LAX",new List<string>{
                            "LAS1",
                    }
                },
                    {
                        "SMF3,95206,LAX",new List<string>{
                            "SMF3",
                    }
                },
                {
                        "GYR2,85395,LAX",new List<string>{
                            "GYR2",
                    }
                },
                {
                        "GYR3,85043,LAX",new List<string>{
                            "GYR3",
                    }
                },
                {
                        "FTW1,75241,LAX",new List<string>{
                            "FTW1",
                    }
                },
                {
                        "MDW2,60433,ORD",new List<string>{
                            "MDW2",
                    }
                },
                {
                        "IND9,46143,ORD",new List<string>{
                            "IND9",
                    }
                },
                {
                        "MQJ1,46140,ORD",new List<string>{
                            "MQJ1",
                    }
                },
                 {
                        "MEM1,38118,ORD",new List<string>{
                            "MEM1",
                    }
                },
                  {
                        "CLT2,28214,ORD",new List<string>{
                            "CLT2",
                    }
                },
                {
                        "ABE8,08513,ORD",new List<string>{
                            "ABE8",
                    }
                },
            };
                if (d.Any(x => x.Value.Contains(v)))
                {
                    var port = d.FirstOrDefault(x => x.Value.Contains(v));
                    return port.Key;
                }
            }
            return string.Empty;
        }

        public class SMPCP
        {
            public string Zone { get; set; }

            public bool IsResidential
            {
                get; set;
            }

            /// <summary>
            /// 
            /// </summary>
            public string TrackingNumber { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string State { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string City { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string Stree { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string ComputeDate { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string Weight { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string ZipCode { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string OrderQty { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string Width { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string Length { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string Height { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string Port { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public int ExpenseItemId { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string CountryCode { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string M3 { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string GoodsDeclareValue { get; set; }
        }

        public class SMPCRItem
        {
            /// <summary>
            /// 
            /// </summary>
            public string ExpenseVersion { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public int DetailId { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public int VersionId { get; set; }
            /// <summary>
            /// UPS佣金
            /// </summary>
            public string ExpenseName { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public bool IsSuccess { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public double Amount { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string Currency { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string BillCurrency { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public double SettlementRate { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public double AmountinOriginalCurrency { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public int ExpenseId { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public int ExpenseItemId { get; set; }
            /// <summary>
            /// 空分区
            /// </summary>
            public string Zones { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public int ApportionMethod { get; set; }

            public string Message { get; set; }
        }

        public class SMPCR
        {
            /// <summary>
            /// 
            /// </summary>
            public int code { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public bool success { get; set; }
            /// <summary>
            /// 成功
            /// </summary>
            public string message { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public List<SMPCRItem> data { get; set; }
        }

        /// <summary>
        /// 计费设置相关的费用
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<ApiJsonModel> Charges(ExpressFeechargesModel t)
        {
            //if (flag)
            //{ 
            int[] esbIdsList = new int[1] { 199 };
            if (t.BillingWeight <= 0 && !esbIdsList.Contains(t.PublicExpressId))
                return ApiJsonModel.Error("重量必须大于0");
            double gWeight = (double)(t.BillingWeight * 1000);

            //空派的特殊计费
            int[] kpIdList = new int[] { 257, 366, 367, 368, 369, 345, 358, 413, 416, 417, 418, 489, 518, 517, 516, 515, 514, 513, 520, 532, 533, 567 };//, 414, 415
                                                                                                                                                   //复杂计费使用SMP系统数据处理
            int[] lastIdList = new int[2] { 34, 433 };
            //快递的走结算价
            //int[] kdIdList = new int[2] { 48, 50 };
            int[] kdIdList = new int[] { };
            if (esbIdsList.Contains(t.PublicExpressId))
            {
                if (t.IsChargeBranchCompany)
                    return ApiJsonModel.Error("分公司暂不计算");
                t.SettlementAmount = 0m;
                t.SettlementCurrency = "USD";
                t.SettlementRate = 1;
                t.AmountinOriginalCurrency = t.SettlementAmount;
                t.Currency = "USD";
                t.PriceVersion = 0;
                t.AmountinOriginalCurrency = t.AmountinOriginalCurrency;
                t.SettlementAmount = t.SettlementAmount;
                var otherFee = new List<dynamic> {
                    new { ExpenseName= "UPS单号使用费", BillCurrency="USD", AmountinOriginalCurrency= 0.1428 },
                    new { ExpenseName= "UPS服务费", BillCurrency="USD", AmountinOriginalCurrency= 0.2857  }
                }
                    .Select(x =>
                    x.ExpenseName + "#"
                    + x.BillCurrency + "#"
                    + (decimal)Math.Round(x.AmountinOriginalCurrency, 4, MidpointRounding.AwayFromZero));
                t.FeeDescription = String.Join(",", otherFee.ToArray());
                return ApiJsonModel.OK(t);
            }
            else if (lastIdList.Contains(t.PublicExpressId))
            {
                int itemId = 0;
                switch (t.PublicExpressId)
                {
                    case 34:
                        itemId = 191;
                        break;
                    case 433:
                        itemId = 224;
                        break;
                }
                if (t.IsChargeBranchCompany)
                    return ApiJsonModel.Error("分公司暂不计算");
                string url = "http://api.smp.xingyunyi.cn/Compute";
                List<SMPCP> cp = new List<SMPCP>();
                cp.Add(new SMPCP
                {
                    ZipCode = t.ZipCode,
                    City = String.Empty,
                    State = String.Empty,
                    Stree = String.Empty,
                    ComputeDate = t.TransactionTime.ToString_yyyyMMdd(),
                    CountryCode = t.CountryCode,
                    ExpenseItemId = itemId,
                    Length = t.Length.ToString(),
                    Width = t.Width.ToString(),
                    Height = t.Height.ToString(),
                    GoodsDeclareValue = 0.ToString(),
                    M3 = 0.ToString(),
                    Port = "LAX",
                    TrackingNumber = String.Empty,
                    Weight = (t.BillingWeight * 1000m).ToString(),
                    OrderQty = 1.ToString(),
                    IsResidential = t.IsResidential,
                    Zone = "0"
                });
                RestSharp.RestClient client = new RestSharp.RestClient(url);

                RestSharp.RestRequest restRequest = new RestSharp.RestRequest(RestSharp.Method.POST);
                restRequest.AddJsonBody(cp.ToArray());
                var response = client.Execute(restRequest);
                if (response.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    var model = Newtonsoft.Json.JsonConvert.DeserializeObject<SMPCR>(response.Content);
                    if (model.success)
                    {
                        var shopFee = model.data.FirstOrDefault(x => x.ExpenseName == "UPS运费");
                        if (shopFee == null)
                            return ApiJsonModel.Error("未返回UPS运费");
                        if (!shopFee.IsSuccess)
                            return ApiJsonModel.Error("运费计算失败:" + shopFee.Message);

                        //原币种结算
                        t.SettlementAmount = (decimal)Math.Round(shopFee.AmountinOriginalCurrency, 4, MidpointRounding.AwayFromZero);
                        t.SettlementCurrency = shopFee.BillCurrency;
                        t.SettlementRate = 1;
                        t.AmountinOriginalCurrency = t.SettlementAmount;
                        t.Currency = shopFee.BillCurrency;
                        t.PriceVersion = long.Parse(shopFee.ExpenseVersion.Split('T')[0].Replace("-", ""));
                        t.AmountinOriginalCurrency = t.AmountinOriginalCurrency;
                        t.SettlementAmount = t.SettlementAmount;
                        var otherFee = model.data.Where(x => x.IsSuccess && x.ExpenseName != "UPS运费" && x.AmountinOriginalCurrency > 0)
                            .Select(x =>
                            x.ExpenseName + "#"
                            + x.BillCurrency + "#"
                            + (decimal)Math.Round(x.AmountinOriginalCurrency, 4, MidpointRounding.AwayFromZero));
                        t.FeeDescription = String.Join(",", otherFee.ToArray());
                        return ApiJsonModel.OK(t);
                    }
                    else
                    {
                        return ApiJsonModel.Error(model.message);
                    }
                }
                else
                {
                    return ApiJsonModel.Error("SMP接口请求失败:" + response.Content ?? response.ErrorMessage);
                }
            }
            else if (kpIdList.Contains(t.PublicExpressId))
            {
                //
                var fee = (await
                    _unitOfWork.QueryBySqlAsync<dynamic>(@"select top 1 * from Logistics_ExpressFeeBase(nolock) 
                            Where ExpressId = @ExpressId and CustomerId=@CustomerId and EnableTime<@EnableTime order by EnableTime desc",
                            null, new
                            {
                                ExpressId = t.PublicExpressId,
                                CustomerId = t.CustomerId,
                                EnableTime = t.TransactionTime
                            })).FirstOrDefault();
                if (fee == null)
                    return ApiJsonModel.Error("无匹配总报价");
                else
                {
                    //快递类型的空派，只按国家分区
                    if (new List<int>() { 518, 517, 516, 515, 514, 513, 567 }.Contains(t.PublicExpressId))
                    {
                        var details = (await _unitOfWork.QueryBySqlAsync<dynamic>($@" 
                                    select  a.FristWeight,a.FristFee,a.ContinuedWeight,a.ContinuedFee from 
	                                     Logistics_ExpressFeeGrads  (nolock)a 
	                                    where  a.BaseId = {fee.Id} and a.MaxWeight>{gWeight} and Countory = '{t.CountryCode}'
	                                    order by a.MaxWeight
	                                         ")).ToList();
                        var d = details.FirstOrDefault();
                        if (d == null)
                            return ApiJsonModel.Error("无匹配明细报价");
                        if (gWeight - (double)d.FristWeight <= 0)
                        {
                            SetCNYFee(t, (decimal)d.FristFee, 0);
                            t.Remark = (d.ContinuedWeight == 500 ? d.ContinuedFee * 2 : d.ContinuedFee).ToString("0.00") + "/KG";//写死500g
                            t.BillingWeight = d.FristWeight / 1000m;
                        }
                        else
                        {
                            //计费
                            SetCNYFee(t,
                         (decimal)d.FristFee
                         + Math.Ceiling(((decimal)gWeight - (decimal)d.FristWeight) / (decimal)d.ContinuedWeight)
                         * (decimal)d.ContinuedFee
                         , 0);
                            t.Remark = (d.ContinuedWeight == 500 ? d.ContinuedFee * 2 : d.ContinuedFee).ToString("0.00") + "/KG";//写死500g
                        }
                        return ApiJsonModel.OK(t);
                    }
                    else if (fee.AreaType == 2)
                    {
                        //计费类型为2
                        //按分区查找
                        if (t.PublicExpressId == 345)
                        {
                            string zone = getZone(t.Stree) + "区";
                            var details = (await _unitOfWork.QueryBySqlAsync<dynamic>($@" 
                                    select  a.FristWeight,a.FristFee,a.ContinuedWeight,a.ContinuedFee from 
	                                     Logistics_ExpressFeeGrads  (nolock)a 
	                                    where  a.BaseId = {fee.Id} and a.MaxWeight>{gWeight} and Countory = '{zone}'
	                                    order by a.MaxWeight
	                                         ")).ToList();
                            var d = details.FirstOrDefault();
                            if (d == null)
                                return ApiJsonModel.Error("无匹配明细报价");
                            if (gWeight - (double)d.FristWeight <= 0)
                            {
                                SetCNYFee(t, (decimal)d.FristFee, 0);
                                t.Remark = d.ContinuedFee.ToString("0.00") + "/KG";
                                t.BillingWeight = d.FristWeight / 1000;
                            }
                            else
                            {
                                //计费
                                SetCNYFee(t,
                             (decimal)d.FristFee
                             + Math.Ceiling(((decimal)gWeight - (decimal)d.FristWeight) / (decimal)d.ContinuedWeight)
                             * (decimal)d.ContinuedFee
                             , 0);
                                t.Remark = d.ContinuedFee.ToString("0.00") + "/KG";
                            }
                            return ApiJsonModel.OK(t);
                        }
                        else if (new List<int>() { 416, 417, 418, 520 }.Contains(t.PublicExpressId))//海卡三个渠道 特别处理分区
                        {
                            string zone = string.Empty;
                            if (new List<int>() { 520 }.Contains(t.PublicExpressId)) { zone = getZoneByUSKK(t.Stree); }
                            else { zone = getZoneByUSHK(t.Stree); }
                            var details = (await _unitOfWork.QueryBySqlAsync<dynamic>($@" 
                                    select  a.FristWeight,a.FristFee,a.ContinuedWeight,a.ContinuedFee from 
	                                     Logistics_ExpressFeeGrads  (nolock)a 
	                                    where  a.BaseId = {fee.Id} and a.MaxWeight>{gWeight} and Countory = '{zone}'
	                                    order by a.MaxWeight
	                                         ")).ToList();
                            var d = details.FirstOrDefault();
                            if (d == null)
                                return ApiJsonModel.Error("无匹配明细报价");
                            if (gWeight - (double)d.FristWeight <= 0)
                            {
                                SetCNYFee(t, (decimal)d.FristFee, 0);
                                t.Remark = d.ContinuedFee.ToString("0.00") + "/KG";
                                t.BillingWeight = d.FristWeight / 1000m;
                            }
                            else
                            {
                                //计费
                                SetCNYFee(t,
                             (decimal)d.FristFee
                             + Math.Ceiling(((decimal)gWeight - (decimal)d.FristWeight) / (decimal)d.ContinuedWeight)
                             * (decimal)d.ContinuedFee
                             , 0);
                                t.Remark = d.ContinuedFee.ToString("0.00") + "/KG";
                            }
                            return ApiJsonModel.OK(t);
                        }
                        else
                        {
                            var details = (await _unitOfWork.QueryBySqlAsync<dynamic>($@" 
                                    select  LEFT(b.ZipCode,c.StartQty) as ZipSrart ,c.StartQty,a.FristWeight,a.FristFee,a.ContinuedWeight,a.ContinuedFee from Logistics_ExpressFeeArea(nolock)c join
	                                     Logistics_ExpressFeeGrads  (nolock)a on c.ExpressId = a.Expressid and a.BaseId = {fee.Id}
	                                    join Logistics_ExpressFeeAreaDetail(nolock)b on a.Countory=b.AreaCode and a.Expressid=b.ExpressId
	                                    where a.MaxWeight>{gWeight}  
	                                    order by a.MaxWeight	 
	                                         ")).ToList();

                            var d = details.Where(x => t.ZipCode.Substring(0, x.StartQty) == x.ZipSrart).FirstOrDefault();
                            if (d == null)
                                return ApiJsonModel.Error("无匹配明细报价");
                            if (gWeight - (double)d.FristWeight <= 0)
                            {
                                SetCNYFee(t, (decimal)d.FristFee, 0);
                                t.Remark = d.ContinuedFee.ToString("0.00") + "/KG";
                                t.BillingWeight = d.FristWeight / 1000;
                            }
                            else
                            {
                                //计费
                                SetCNYFee(t,
                             (decimal)d.FristFee
                             + Math.Ceiling(((decimal)gWeight - (decimal)d.FristWeight) / (decimal)d.ContinuedWeight)
                             * (decimal)d.ContinuedFee
                             , 0);
                                t.Remark = d.ContinuedFee.ToString("0.00") + "/KG";
                            }
                            return ApiJsonModel.OK(t);
                        }
                    }
                    else
                    {
                        return ApiJsonModel.Error("不支持的计费类型");
                    }
                }
            }
            else if (kdIdList.Contains(t.PublicExpressId) && t.IsChargeBranchCompany)
            {
                try
                {
                    if (t.BillingWeight > 2.5m)
                    {
                        if (t.ExpressId == 204)
                        {
                            t.ExpressId = 201;
                        }
                        if (t.ExpressId == 363)
                        {
                            t.ExpressId = 364;
                        }
                    }
                    var d = _unitOfWork.Connection.Query<Order_FeeResult>("newShippingCharge5", new
                    {
                        ExpressId = t.ExpressId,
                        Weight = t.BillingWeight,
                        CountryCode = t.CountryCode,
                        EffectiveDate = t.TransactionTime,
                        CustomerId = 0,
                        ZipCode = t.ZipCode,
                        Area = string.Empty
                    }, _unitOfWork.Transaction, commandType: System.Data.CommandType.StoredProcedure);
                    if (d.Count() > 0)
                    {
                        var ree = d.First();
                        SetCNYFee(t, ree.Price, 0);
                        return ApiJsonModel.OK(t);
                    }
                    else
                    {
                        return ApiJsonModel.Error("结算费用计算为0");
                    }
                }
                catch (Exception ex)
                {
                    return ApiJsonModel.Error(ex.Message);
                }
            }
            else
            {
                ThreadPool.SetMinThreads(200, 200);
                var fb = new ExpressFeeBase(t.CustomerId, t.PublicExpressId, t.CountryCode, t.TransactionTime, string.Empty);
                var set = await db.SortedSetRangeByScoreAsync(fb.Key, 0, fb.DateTimeVersion, order: Order.Descending, take: 1);
                if (set.Length == 0)
                {
                    return ApiJsonModel.Error("无匹配总报价，请确认是否导入报价");
                }
                else
                {
                    var fee = set[0];
                    var detail = Newtonsoft.Json.JsonConvert.DeserializeObject<ExpressFeeBaseDetail>(fee);
                    if (detail.Data.Count() == 0)
                        return ApiJsonModel.Error($"无匹配明细报价，请确认当前订单国家{t.CountryCode}，是否有报价");
                    if (detail.FeeType == ExpressFeeChargesType.Range)
                    {
                        var d = detail.Data.Where(x => gWeight > (double)x.StartWeight && gWeight <= (double)x.EndWeight).FirstOrDefault();
                        if (d == null)
                            return ApiJsonModel.Error($"无匹配明细报价，请确认当前订单重量{gWeight}，是否有报价");
                        else
                        {
                            SetCNYFee(t, (decimal)d.Fee, detail.DateTimeVersion);
                        }
                    }
                    else if (detail.FeeType == ExpressFeeChargesType.Grads)
                    {
                        var d = detail.Data.Where(x => gWeight <= (double)x.MaxWeight).OrderBy(x => x.MaxWeight).FirstOrDefault();
                        if (d == null)
                            return ApiJsonModel.Error("无匹配明细报价");
                        if (gWeight - (double)d.FristWeight <= 0)
                        {
                            SetCNYFee(t, (decimal)d.FristFee, detail.DateTimeVersion);
                            t.Remark = d.ContinuedFee + "/KG";
                            t.BillingWeight = d.FristWeight / 1000;
                        }
                        else
                        {
                            SetCNYFee(t,
                                (decimal)d.FristFee + Math.Ceiling(((decimal)gWeight - (decimal)d.FristWeight) / (decimal)d.ContinuedWeight) * (decimal)d.ContinuedFee
                                , detail.DateTimeVersion);
                            t.Remark = d.ContinuedFee + "/KG";
                        }
                    }
                    else
                    {
                        return ApiJsonModel.Error("无匹配明细报价");
                    }
                    return ApiJsonModel.OK(t);
                }
            }
            //}
            //else
            //{
            //    return ApiJsonModel.OK();
            //}
        }

        /// <summary>
        /// CNY 费用
        /// </summary>
        /// <param name="t"></param>
        /// <param name="fee"></param>
        /// <param name="priceVersion"></param>
        private static void SetCNYFee(ExpressFeechargesModel t, decimal fee, long priceVersion)
        {
            t.SettlementAmount = fee;
            t.SettlementCurrency = "CNY";
            t.SettlementRate = 1;
            t.AmountinOriginalCurrency = fee;
            t.Currency = "CNY";
            t.PriceVersion = priceVersion;
            t.AmountinOriginalCurrency = t.AmountinOriginalCurrency;
            t.SettlementAmount = t.SettlementAmount;
        }
    }
}
