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.Core.Standard.Data.Redis;
using XYY.Service.Standard.Finance.Charging.Base;
using XYY.Service.Standard.Finance.Charging.Express;
using Dapper;
using NCalc;
using XYY.Core.Standard.Mvc;
using NPOI.SS.Formula;
using System.Threading;

namespace XYY.Service.Standard.Finance.Charging.FeeFormula
{
    /// <summary>
    /// 运费计算公式补充
    /// </summary>
    public interface IFormulaService : IChargesService<ExpressFeechargesModel>
    {
        Task<ApiJsonModel> LoadOtherByChannelIds(List<int> expressId);

        Task<ApiJsonModel> LoadOther(int expressId = 0, int customerId = 0);
        /// <summary>
        /// 预缓存计算公式
        /// </summary>
        /// <returns></returns>
        Task<ApiJsonModel> LoadFormula(int expressId = 0, int customerId = 0);
    }

    public class FormulaService : IFormulaService
    {
        IUnitOfWork _unitOfWork;
        IDatabase db;
        IServer server;
        public FormulaService(IUnitOfWork unitOfWork, RedisHelper helper)
        {
            _unitOfWork = unitOfWork;
            this.db = helper.GetDatabase();
            this.server = helper.GetServer();
        }

        public async Task<ApiJsonModel> Charges(ExpressFeechargesModel t)
        {
            ThreadPool.SetMinThreads(200, 200);
            if (t.PublicExpressId != 48 && t.PublicExpressId != 50)
            {
                string formulaTrim = "";
                //取计费公式
                FormulaBase formulaBase = new FormulaBase(t.TransactionTime, t.CustomerId, t.PublicExpressId, null);
                var set = await db.SortedSetRangeByScoreAsync(formulaBase.Key, 0, formulaBase.DateTimeVersion, order: Order.Descending, take: 1);
                if (set.Length == 0)
                    return ApiJsonModel.OK();
                string formula = set[0];
                //格式清理，只读取需要的值
                formulaTrim =
                  formula.Replace("@", "").Replace("原价", "").Replace("(", "").Replace(")", "").Replace("*", " ").Replace("+", " ").Replace("-", " ").Replace("/", "");




                Dictionary<string, decimal> otherList = new Dictionary<string, decimal>();
                foreach (var item in formulaTrim.Split(' ', StringSplitOptions.RemoveEmptyEntries))
                {
                    var otherBath = new OtherBase(t.TransactionTime, t.PublicExpressId, t.CustomerId, item, 0);
                    var otherSet = await db.SortedSetRangeByScoreAsync(otherBath.Key, 0, formulaBase.DateTimeVersion, order: Order.Descending, take: 1);
                    if (otherSet.Length == 0)
                        return ApiJsonModel.OK();
                    otherList.Add(item, (decimal)(double)otherSet[0]);
                }
                foreach (var item in otherList)
                {
                    //替换公式
                    formula = formula.Replace(item.Key, item.Value.ToString());
                }
                formula = formula.Replace("原价", t.AmountinOriginalCurrency.ToString()).Replace("@", "");
                //计算公式值
                decimal fee = Convert.ToDecimal(new Expression(formula).Evaluate());
                t.SettlementAmount = fee;
                t.AmountinOriginalCurrency = fee;
                return ApiJsonModel.OK();
            }
            else
            {
                //FEDEX和DHL写死，不要读来读去了
                decimal otherFee = (_unitOfWork.Connection.QuerySingle<decimal>("select top 1 Price from Logistics_Fee_Other(nolock)  " +
                    "where  ExpressId = @PubicExpressId AND CustomerId =0 and feetype=2  AND EffectiveDate <= @EffectiveDate  order by  EffectiveDate DESC  ",
                     new { PubicExpressId = t.PublicExpressId, EffectiveDate = t.TransactionTime }
                ));
                t.SettlementAmount = t.AmountinOriginalCurrency * (1 + otherFee);
                t.AmountinOriginalCurrency = t.SettlementAmount;
                return ApiJsonModel.OK();
            }
        }


        public async Task<ApiJsonModel> LoadFormula(int expressId = 0, int customerId = 0)
        {
            try
            {
                ThreadPool.SetMinThreads(200, 200);
                #region 操作

                var batch = db.CreateBatch();
                List<Task> tasks = new List<Task>();
                Task t3 = null;
                if (expressId == 0 && customerId == 0)
                {
                    //清理所有 
                    //await db.DeleteScanKey( "Formula*");
                    t3 = db.DeleteScanKey(batch, "Formula*");
                    if (t3 != null)
                        tasks.Add(t3);
                }
                else if (expressId != 0 && customerId != 0)
                {
                    //清理线路的公式
                    this.db.KeyDelete($"Formula{customerId.ToString("00000")}{expressId.ToString("00000")}");
                }
                else if (expressId != 0)
                {
                    t3 = db.DeleteScanKey(batch, $"Formula0*{expressId.ToString("00000")}*");
                    if (t3 != null)
                        tasks.Add(t3);
                }

                string where = "";
                if (expressId != 0)
                {
                    where += $" and ExpressId={expressId}";
                }
                if (customerId != 0)
                {
                    where += $" and CustomerId={customerId}";
                }
                string sql = $@"
                  select distinct ExpressId,EffectiveDate,CustomerId,Formula from Logistics_Fee_Formula(nolock)
                    where CustomerId<>0 {where}
                  order by CustomerId,ExpressId,EffectiveDate";

                var list = await _unitOfWork.QueryBySqlAsync<dynamic>(sql);
                //var group = list.GroupBy(x => new { x.ExpressId, x.EffectiveDate, x.CustomerId });
                foreach (var item in list)
                {
                    FormulaBase formulaBase = new FormulaBase(item.EffectiveDate, item.CustomerId, item.ExpressId, item.Formula);
                    tasks.Add(batch.SortedSetAddAsync(formulaBase.Key, formulaBase.Formula, formulaBase.DateTimeVersion));
                }

                batch.Execute();
                Task.WaitAll(tasks.ToArray());
                #endregion
            }
            catch (Exception ex)
            {
                return ApiJsonModel.Error(ex.Message);
            }
            return ApiJsonModel.OK("成功");
        }

        public async Task<ApiJsonModel> LoadOther(int expressId = 0, int customerId = 0)
        {
            try
            {
                ThreadPool.SetMinThreads(200, 200);
                var batch = db.CreateBatch();
                List<Task> tasks = new List<Task>();
                Task t3 = null;
                string key = null;
                if (expressId == 0 && customerId == 0)
                {
                    key = "Other*";
                }
                else if (expressId != 0 && customerId != 0)
                {
                    //清理线路的公式
                    key = $"Other*{customerId.ToString("00000")}{expressId.ToString("00000")}";

                }
                else if (expressId != 0)
                {
                    key = $"Other0*{expressId.ToString("00000")}";
                }
                else if (customerId != 0)
                {
                    key = $"Other*{customerId.ToString("00000")}*";
                }
                t3 = db.DeleteScanKey(batch, key);
                if (t3 != null)
                    tasks.Add(t3);


                string where = "";
                if (expressId != 0)
                {
                    where += $" and ExpressId={expressId}";

                }
                if (customerId != 0)
                {
                    where += $" and CustomerId={customerId}";
                }


                string sql = $@"
                              select ExpressId,FeeType,Price,EffectiveDate,CustomerId from Logistics_Fee_Other(nolock) where CustomerId<>0 and IsEffective=1
                                    and FeeType<>1 {where}
                              order by  CustomerId,ExpressId,FeeType,EffectiveDate";
                var list = await _unitOfWork.QueryBySqlAsync<dynamic>(sql);
                foreach (var item in list)
                {
                    OtherBase otherBase = new OtherBase(item.EffectiveDate, item.ExpressId, item.CustomerId, new OtherFeeType(item.FeeType).ToString(), item.Price);
                    tasks.Add(batch.SortedSetAddAsync(otherBase.Key, otherBase.Price.ToString("0.0000"), otherBase.DateTimeVersion));
                }
                batch.Execute();
                Task.WaitAll(tasks.ToArray());
            }
            catch (Exception ex)
            {
                return ApiJsonModel.Error(ex.Message);
            }
            return ApiJsonModel.OK("成功");
        }


        public async Task<ApiJsonModel> LoadOtherByChannelIds(List<int> expressIds)
        {
            if (expressIds?.Any() == true)
            {
                foreach (var expressId in expressIds)
                {
                    var result = await LoadOther(expressId);
                    if (!result.success)
                    {
                        string msg = $"清理FeeOther失败,ExpressId:{expressId}";
                        return ApiJsonModel.Error(msg);
                    }
                }
            }
            return ApiJsonModel.OK("成功");
        }
    }


}
