using Com.Bocom.OpenApi;
using Kivii;
using Kivii.Finances.Entities;
using Kivii.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Njzj.Bocoms.Openapis
{
    public class WriteOffJob : IJob
    {
        public string Name => "智慧记账账单核销";

        public string Description => "智慧记账账单自动核销";

        public IJobContext TaskContext { get; set; }

        public void Dispose()
        {
        }

        public bool Execution()
        {
            #region 获取通知,且过滤哪些通知已经作废或者匹配不上的
            var connE = KiviiContext.GetOpenedDbConnection<WriteOffResultNotify>();

            var query = connE.From<WriteOffResultNotify>();
            query.Where(o => o.Status != int.MaxValue);
            var writeOffs = connE.Select(query);
            if (writeOffs.IsNullOrEmpty())
            {
                TaskContext.Message = "暂无核销通知需处理!";
                return true;
            }
            var bizKvids = writeOffs.ConvertAll(o => o.BizKvid);
            if (bizKvids.IsNullOrEmpty())
            {
                var updateWriteOffs=connE.From<WriteOffResultNotify>();
                updateWriteOffs = updateWriteOffs.Update(o => o.Status);
                updateWriteOffs = updateWriteOffs.Where(o => Sql.In(o.BizKvid, bizKvids));
                connE.UpdateOnly(new WriteOffResultNotify { Status = int.MaxValue }, updateWriteOffs);
                TaskContext.Message = "暂无核销通知需处理!";
                return true;
            }

            var connF = KiviiContext.GetOpenedDbConnection<Settlement>();
            var settlements = connF.Select<Settlement>(o => Sql.In(o.Kvid, bizKvids));
            if (settlements.IsNullOrEmpty())
            {
                var updateWriteOffs = connE.From<WriteOffResultNotify>();
                updateWriteOffs = updateWriteOffs.Update(o => o.Status);
                updateWriteOffs = updateWriteOffs.Where(o => Sql.In(o.BizKvid, bizKvids));
                connE.UpdateOnly(new WriteOffResultNotify { Status = int.MaxValue }, updateWriteOffs);
                TaskContext.Message = "暂无核销通知需处理!";
                return true;
            }
            var preSettlements = settlements.Where(o => o.AmountPayment == 0).ToList();//需要进行匹配核销的结算
            var notMatchBizKvids=new List<Guid>();
            foreach (var kvid in bizKvids)
            {
                if (!preSettlements.Exists(o => o.Kvid == kvid)) notMatchBizKvids.Add(kvid);
            }
            if (!notMatchBizKvids.IsNullOrEmpty())
            {
                var updateWriteOffs = connE.From<WriteOffResultNotify>();
                updateWriteOffs = updateWriteOffs.Update(o => o.Status);
                updateWriteOffs = updateWriteOffs.Where(o => Sql.In(o.BizKvid, notMatchBizKvids));
                connE.UpdateOnly(new WriteOffResultNotify { Status = int.MaxValue }, updateWriteOffs);
            }
            writeOffs.RemoveAll(o => Sql.In(o.BizKvid, notMatchBizKvids));
            var matchWriteOffs = new List<WriteOffResultNotify>();
            var payments = new List<Payment>();
            foreach (var item in writeOffs)
            {
                if (item.biz_content.bill_wo_state != "03")
                {
                    TaskContext.Message = $"Error:10001,[{item.BillId}]账单核销状态不是03-全额核销!";
                    continue;
                }
                bool matched = false;
                foreach (var pay in item.biz_content.pay_detail_list)
                {
                    var split = pay.vch_no.Split('-');
                    if (split.Length != 3)
                    {
                        TaskContext.Message = $"Error:10002,[{item.BillId}]vch_no号格式不符合Split规则!";
                        continue;
                    }
                    var serialNumber = split[1];
                    if (serialNumber.IsNullOrEmpty())
                    {
                        TaskContext.Message = $"Error:10003,[{item.BillId}]vch_no截取的流水号是空!";
                        continue;
                    }
                    var payment = connF.Single<Payment>(o => o.SerialNumber == serialNumber && o.OffsetKvid == Guid.Empty && o.Type == PaymentType.Bank);
                    if (payment == null)
                    {
                        TaskContext.Message = $"Error:20001,[{item.BillId}]未找到此流水号[{serialNumber}]的到账信息!";
                        continue;
                    }
                    payments.Add(payment);
                    matched = true;
                }
                if (matched) matchWriteOffs.Add(item);
            }
            if (matchWriteOffs.IsNullOrEmpty())
            {
                TaskContext.Message = $"{writeOffs.Count}条待处理通知,尚未匹配到流水信息!";
                return true;
            }
            #endregion
            #region  合并数据库连接,并启用事务
            IDbTransaction tranE = null, tranF = null;
            //if (connE.ConnectionString == connR.ConnectionString)//现在的连接会自动取缓存

            if (connE == connF)
            {
                //两个连接是同一个，缓存生效,不做任何操作
            }
            else if (connE.ConnectionString == connF.ConnectionString)//连接对象不同，但连接字符串是一样的，因为在本环节中，连接没有被污染，可以关了一个连接
            {
                connF.Close();
                connF = connE;
            }

            if ((connE is LinqConnection) && (connE as LinqConnection).Transaction == null)
            {
                tranE = connE.OpenTransaction();
            }
            if ((connF is LinqConnection) && (connF as LinqConnection).Transaction == null)
            {
                tranF = connF.OpenTransaction();
            }
            #endregion
            try
            {
                foreach (var settlement in preSettlements)
                {
                    var writeOff = matchWriteOffs.FirstOrDefault(o => o.BizKvid == settlement.Kvid);
                    if (writeOff == null)
                    {
                        TaskContext.Message = $"Error:10004,[{settlement.Kvid}]未找到此账单通知信息!";
                        continue;
                    }
                    var currentPayments = new List<Payment>();
                    var payingMethods = new List<PayingMethod>();
                    foreach (var pay in writeOff.biz_content.pay_detail_list)
                    {
                        var splitSerial = pay.vch_no.Split('-');
                        if (splitSerial.Length != 3)
                        {
                            TaskContext.Message = $"Error:10005,[{writeOff.BillId}]vch_no号格式不符合Split规则!";
                            continue;
                        }
                        var serialNumber = splitSerial[1];
                        if (serialNumber.IsNullOrEmpty())
                        {
                            TaskContext.Message = $"Error:10006,[{writeOff.BillId}]vch_no截取的流水号是空!";
                            continue;
                        }
                        var payment = payments.FirstOrDefault(o => o.SerialNumber == serialNumber);
                        if (payment == null)
                        {
                            TaskContext.Message = $"Error:20002,[{writeOff.BillId}]未找到此流水号[{serialNumber}]的到账信息!";
                            continue;
                        }
                        var amountTotal = pay.jnl_write_off_amt.ToDecimal();
                        if (payment.Amount - payment.AmountUsed < amountTotal)
                        {
                            TaskContext.Message = $"Error:20003,流水[{payment.SerialNumber}]可用金额不足!";
                            continue;
                        }
                        //var splits = connF.Select<Payment>(o => o.RootKvid==payment.Kvid && o.OwnerKvid == settlement.OwnerKvid && o.OffsetKvid == Guid.Empty && o.Type == PaymentType.Split && o.Currency == settlement.Currency);
                        var splits = connF.Select<Payment>(o => o.RootKvid== payment.Kvid && o.OffsetKvid == Guid.Empty && o.Type == PaymentType.Split && o.Currency == settlement.Currency);
                        if (splits.IsNullOrEmpty())
                        {
                            TaskContext.Message = $"Error:20004,流水[{payment.SerialNumber}]暂未认领!";
                            continue;
                        }
                        foreach (var split in splits)
                        {
                            if (amountTotal <= 0) continue;
                            var amountSplit = split.Amount - split.AmountUsed;
                            if (amountSplit <= 0) continue;
                            if (amountSplit >= amountTotal)
                            {
                                var payingMethod = new PayingMethod();
                                payingMethod.Amount = amountTotal;
                                payingMethod.Type = PayType.Payment;
                                payingMethod.Kvid = split.Kvid;
                                payingMethod.Remark = $"智慧记账自动核销,核销订单号:{writeOff.BillId}";
                                payingMethods.Add(payingMethod);
                                currentPayments.Add(split);
                                amountTotal -= amountTotal;
                            }
                            else
                            {
                                var payingMethod = new PayingMethod();
                                payingMethod.Amount = amountSplit;
                                payingMethod.Type = PayType.Payment;
                                payingMethod.Kvid = split.Kvid;
                                payingMethod.Remark = $"智慧记账自动核销,核销订单号:{writeOff.BillId}";
                                payingMethods.Add(payingMethod);
                                currentPayments.Add(split);
                                amountTotal -= amountSplit;
                            }
                        }
                        
                    }
                    if (!currentPayments.IsNullOrEmpty())
                    {
                        if (Extension.AutoPay(currentPayments, settlement, payingMethods, connF))
                        {
                            writeOff.Status = int.MaxValue;
                            writeOff.AddOnlyProperties(o => o.Status);
                            connE.UpdateOnly(writeOff);
                        }
                    }
                }

                tranE?.Commit();
                tranF?.Commit();
            }
            catch (Exception ex)
            {
                tranE?.Rollback();
                tranF?.Rollback();
                throw ex;
            }
            
            return true;
        }
    }
}
