using Dapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XYY.Core.Standard;
using XYY.Core.Standard.Data.Infrastructure;
using XYY.Core.Standard.Mvc;
using XYY.Model.Standard;
using XYY.Model.Standard.Finance;
using XYY.Service.Standard.Finance.Charging.Base;
using XYY.Service.Standard.Finance.Charging.CustomerAccount;
using XYY.Service.Standard.Finance.Charging.Express;

namespace XYY.Service.Standard.Finance.Charging.CustomerOrderFee
{
    #region interface
    public interface ICustomerladingBillFeeService
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="financeLadingBillDto"></param>
        /// <returns></returns>
        Task<ApiJsonModel> Charges(FinanceLadingBillDto financeLadingBillDto);
        /// <summary>
        /// 仅抵账操作
        /// </summary>
        /// <param name=""></param>
        /// <returns></returns>
        Task<ApiJsonModel> OnlyRepayCharges(int LadingBillId);
    }
    #endregion

    public class CustomerladingBillFeeService : ICustomerladingBillFeeService
    {
        #region 构造
        private string billType => "客户头程账单费用";
        private string IncomeOrESxpense => "支出";
        private IUnitOfWork _unitOfWork;
        private ICustomerAccountService _customerAccountService;
        public CustomerladingBillFeeService(IUnitOfWork unitOfWork
            , ICustomerAccountService customerAccountService)
        {
            this._unitOfWork = unitOfWork;
            this._customerAccountService = customerAccountService;
        }
        #endregion

        #region 私有
        /// <summary>
        /// 计费
        /// </summary>
        /// <param name="t"></param>
        /// <param name="shopFee"></param>
        /// <param name="tax"></param>
        /// <param name="attache"></param>
        /// <param name="waitBanks"></param>
        /// <returns></returns>
        private async Task<bool> Bookkeeping(List<Finance_ChargesDetail> newChargesDetails, Finance_ChargesDetail oldData = null)
        {
            try
            {
                await _unitOfWork.BulkToDBAsync(newChargesDetails);
                if (oldData != null) { await _unitOfWork.UpdateAsync(oldData); }
                //计算费用
                decimal cost = 0;
                var income = newChargesDetails.Where(x => x.IncomeOrESxpense == "收入").ToList();
                var expend = newChargesDetails.Where(x => x.IncomeOrESxpense == "支出").ToList();
                cost = expend.Sum(x => x.SettlementAmount) - income.Sum(x => x.SettlementAmount);
                //更新运费，失败时回滚所有操作
                if (!await _customerAccountService.Deduction(oldData?.CustomerId ?? newChargesDetails.FirstOrDefault().CustomerId, cost, false))
                {
                    _unitOfWork.Rollback();
                    return false;
                }
                else
                {
                    _unitOfWork.Commit();
                    return true;
                }
            }
            catch (Exception ex)
            {
                _unitOfWork.Rollback();
                return false;
            }
        }
        /// <summary>
        /// 初始化操作实体
        /// </summary>
        /// <param name="old"></param>
        private List<Finance_ChargesDetail> InitializeChargesDetailModel(FinanceLadingBillDto billDto, ref Finance_ChargesDetail oldData)
        {
            List<Finance_ChargesDetail> newChargesDetails = new List<Finance_ChargesDetail>();
            if (billDto==null&&oldData==null) { return newChargesDetails; }//异常情况的数据，不处理
            DateTime accountingDate = DateTime.Now;
            string sqlWhere = string.Empty;
            if (billDto != null) { sqlWhere = $" and a.ServiceName='{billDto.CustomerName}' "; } else { sqlWhere = $" and b.Id={oldData.CustomerId} "; }
            int? customerId = _unitOfWork.QueryBySqlAsync<BaseEntity>($" select b.Id from Logistics_FirstService(nolock) a left join User_Customer(nolock) b on b.Id=a.CustomerId where 1=1 {sqlWhere}  ").Result?.FirstOrDefault()?.Id;
            if (customerId == null || customerId == 0) { return newChargesDetails; }//没有客户信息 做不了记账
            if (oldData != null)
            {
                string tip = string.Empty; bool repay = false;
                if (billDto==null) { tip = "账单删除"; repay = true; }
                else if (billDto.CusetomerFee != oldData.SettlementAmount) { tip = "计费金额"; repay = true; }
                else if (customerId != oldData.CustomerId) { tip = "计费客户"; repay = true; }
                else if (billDto.CustomerIncomeCurrency != oldData.SettlementCurrency) { tip = "计费币种"; repay = true; }
                else if (billDto.CustomerBillTime != oldData.TransactionTime) { tip = "计费时间"; repay = true; }
                if (!repay) { return newChargesDetails; }//无抵账操作返回
                //抵账数据
                newChargesDetails.Add(new Finance_ChargesDetail()
                {
                    BillNo = oldData.BillNo,
                    BillType = oldData.BillType,
                    AccountingDate = accountingDate,
                    TransactionType = (int)TransactionType.Consume,
                    TransactionNo = "first" + accountingDate.ToString("yyyyMMddHHmmssfff")+'d',
                    ChargeName = "头程帐单抵账",
                    TransactionTime = oldData.TransactionTime,
                    IncomeOrESxpense = "收入",
                    Currency = oldData.Currency,
                    AmountinOriginalCurrency = oldData.AmountinOriginalCurrency,
                    SettlementCurrency = oldData.SettlementCurrency,
                    SettlementAmount = oldData.SettlementAmount,
                    Offset = true,
                    FeeDescription = $"{tip}变更抵账：{oldData.TransactionNo}",
                    CustomerId = oldData.CustomerId,
                    CreateTime = accountingDate,
                    AccountingNo = "ANO" + DateTime.Now.ToString("yyyyMMddHHmmssfff")+'d',
                    BillingWeight =  oldData.BillingWeight,
                    SettlementCompleted = true,
                });
                //新账 删除操作无新账,只有抵账
                if (billDto != null)
                {
                    newChargesDetails.Add(new Finance_ChargesDetail()
                    {
                        BillNo = billDto.BillNumber,
                        BillType = billType,
                        AccountingDate = accountingDate,
                        TransactionType = (int)TransactionType.Consume,
                        TransactionNo = "first" + accountingDate.ToString("yyyyMMddHHmmssfff"),
                        ChargeName = "头程帐单收款",
                        TransactionTime = billDto.CustomerBillTime ?? accountingDate,
                        IncomeOrESxpense = IncomeOrESxpense,
                        Currency = billDto.FristCurrency,
                        AmountinOriginalCurrency =  billDto.CusetomerFee,
                        SettlementCurrency = billDto.CustomerIncomeCurrency,
                        SettlementAmount =  billDto.CusetomerFee,
                        Offset = false,
                        CustomerId = customerId ?? 0,
                        CreateTime = accountingDate,
                        AccountingNo="ANO"+DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                        BillingWeight= billDto.Weight,
                        SettlementCompleted = false,
                    });
                }
                //旧账数据为抵账数据
                oldData.Offset = true;
            }
            else
            {
                newChargesDetails.Add(new Finance_ChargesDetail()
                {
                    BillNo = billDto.BillNumber,
                    BillType = billType,
                    AccountingDate = accountingDate,
                    TransactionType = (int)TransactionType.Consume,
                    TransactionNo = "first" + accountingDate.ToString("yyyyMMddHHmmssfff"),
                    ChargeName = "头程帐单收款",
                    TransactionTime = billDto.CustomerBillTime ?? accountingDate,
                    IncomeOrESxpense = IncomeOrESxpense,
                    Currency = billDto.FristCurrency,
                    AmountinOriginalCurrency = billDto.CusetomerFee,
                    SettlementCurrency = billDto.CustomerIncomeCurrency,
                    SettlementAmount =  billDto.CusetomerFee,
                    Offset = false,
                    CustomerId = customerId ?? 0,
                    CreateTime = accountingDate,
                    AccountingNo = "ANO" + DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                    BillingWeight =  billDto.Weight,
                    SettlementCompleted=false,
                });
            }
            return newChargesDetails;
        }
        #endregion

        #region 实现
        public async Task<ApiJsonModel> Charges(FinanceLadingBillDto billDto)
        {
            string sql = $@"select *from Finance_ChargesDetail where BillNo='{billDto.BillNumber}' and Offset=0 ";//提单号查询所有
            var dbList = await _unitOfWork.QueryBySqlAsync<Finance_ChargesDetail>(sql);
            var dbOp = dbList?.FirstOrDefault();
            var opList = InitializeChargesDetailModel(billDto, ref dbOp);
            if (opList == null || opList.Count == 0) { return ApiJsonModel.OK("无可操作数据！"); }
            if (await Bookkeeping(opList, dbOp))
            {
                return ApiJsonModel.OK("成功");
            }
            else
            {
                return ApiJsonModel.Error("欠费");
            }
        }
        public async Task<ApiJsonModel> OnlyRepayCharges(int LadingBillId)
        {
            string sql = $@"select *from Finance_ChargesDetail(nolock) where BillNo=(select BillNumber from Finance_Logistics_LadingBill(nolock) where Id={LadingBillId}) and Offset=0 ";//提单号查询所有
            var dbList = await _unitOfWork.QueryBySqlAsync<Finance_ChargesDetail>(sql);
            var dbOp = dbList?.FirstOrDefault();
            var opList = InitializeChargesDetailModel(null, ref dbOp);
            if (opList == null || opList.Count == 0) { return ApiJsonModel.OK("无可操作数据！"); }
            if (await Bookkeeping(opList, dbOp))
            {
                return ApiJsonModel.OK("成功");
            }
            else
            {
                return ApiJsonModel.Error("欠费");
            }
        }
        #endregion

    }
}
