using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using MS.Common.IDCode;
using MS.Component.Jwt;
using MS.Component.Jwt.UserClaim;
using MS.DbContexts;
using MS.Entities;
using MS.Entities.AccountingService_Models;
using MS.Entities.AuthService_Models;
using MS.Models;
using MS.Models.ViewModel;
using MS.UnitOfWork;
using MS.WebCore;
using MS.WebCore.Core;
using Newtonsoft.Json;
using NPOI.POIFS.Crypt.Dsig;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace MS.Services
{
    public class AccountService : BaseService, IAccountService
    {
        private readonly JwtService _jwtService;
        private readonly SiteSetting _siteSetting;
        public RedisExample redisExample = new RedisExample();
        bool ihostSyncRepLost = true;

        public AccountService(JwtService jwtService, IOptions<SiteSetting> options, IUnitOfWork<MSDbContext> unitOfWork, IMapper mapper, IdWorker idWorker, IClaimsAccessor claimsAccessor, IStringLocalizer localizer, IUnitOfWork<AccountingContext> AccountingContext, IUnitOfWork<SQLiteContext> SQLiteContext, IUnitOfWork<AuthContext> AuthContext) : base(unitOfWork, mapper, idWorker, claimsAccessor, localizer, AccountingContext, SQLiteContext, AuthContext)
        {
            _jwtService = jwtService;
            _siteSetting = options.Value;
        }
        public async Task<ExecuteResult<UserData>> Login(LoginViewModel viewModel)
        {
            var result = await viewModel.LoginValidate(_unitOfWork, _mapper, _siteSetting, _localizer);
            if (result.IsSucceed)
            {
                result.Result.Token = _jwtService.BuildToken(_jwtService.BuildClaims(result.Result));
                return new ExecuteResult<UserData>(result.Result);
            }
            else
            {
                return new ExecuteResult<UserData>(result.Message);
            }
        }
        public async Task<ExecuteResult<UserData>> syncFromVersion(long versionNo, bool excludingCurrentBu, string specificHeader)
        {
            ChangeHistory ch = new ChangeHistory();
            var SiteDevices = _AuthContext.GetRepository<SiteDevices>().GetAll()
                   .Where(a => a.HardwareIdentity == specificHeader).FirstOrDefault();
            var buid = SiteDevices.AsSubjectOfBusinessUnitId;
            var acct = _AccountingContext.GetRepository<BusinessUnitInfo>().GetAll().Where(a => a.Id == buid).FirstOrDefault();
            var CurrentBuId = acct.BusinessUnitInfoId;
            var originalBuId = acct.Id;
            if (versionNo == 0)
            {
                ch = _AccountingContext.GetRepository<ChangeHistory>().GetAll().OrderByDescending(a => a.TableName == -2).FirstOrDefault();
            }
            else
            {
                ch = _AccountingContext.GetRepository<ChangeHistory>().GetAll().OrderByDescending(a => a.Id).FirstOrDefault();
            }
            var lastModified = ch.LastModified;
            var currentVersionNo = ch.Id;

            if (versionNo == 0)
            {
                getAllRecordsToBeSynced(CurrentBuId, originalBuId, lastModified, excludingCurrentBu);
            }
            else
            {
                getRecordsGreaterThanVersionNo(CurrentBuId, originalBuId, versionNo, currentVersionNo, excludingCurrentBu);
            }

            return null;
        }
        public async Task<ChangeHistoryResponse> getAllRecordsToBeSynced(Guid? buid, Guid? originalBuId, DateTime? lastModified, bool excludingCurrentBu)
        {
            ChangeHistoryResponse changeHistoryResponse = new ChangeHistoryResponse();
            try
            {


                if (excludingCurrentBu)
                {
                    var dbCardInfo = await _AccountingContext.GetRepository<CardInfo>().FromSql(string.Format(@"
              select 
        cardinfo0_.id , 
        cardinfo0_.account_info_id, 
        cardinfo0_.account_id , 
        cardinfo0_.b_limit_car , 
        cardinfo0_.business_unit_info_id , 
        cardinfo0_.bu_info_created_id , 
        cardinfo0_.card_status , 
        cardinfo0_.ctc , 
        cardinfo0_.ctc_flag , 
        cardinfo0_.ctc_time , 
        cardinfo0_.card_class , 
        cardinfo0_.card_id , 
        cardinfo0_.card_no , 
        cardinfo0_.card_sno , 
        cardinfo0_.card_type , 
        cardinfo0_.car_license_no , 
        cardinfo0_.d_max_pay , 
        cardinfo0_.discount_no, 
        cardinfo0_.enable_sms , 
        cardinfo0_.gid , 
        cardinfo0_.holder , 
        cardinfo0_.points_awarded_total , 
        cardinfo0_.creation_date , 
        cardinfo0_.last_modified , 
        cardinfo0_.limit_times , 
        cardinfo0_.lmt_good , 
        cardinfo0_.lmt_oil , 
        cardinfo0_.m_max_pay , 
        cardinfo0_.balance, 
        cardinfo0_.once_max_pay , 
        cardinfo0_.operator_no, 
        cardinfo0_.expiration_date, 
        cardinfo0_.phone_no , 
        cardinfo0_.deposit_balance , 
        cardinfo0_.recharge_total, 
        cardinfo0_.sno, 
        cardinfo0_.activation_date , 
        cardinfo0_.tmac, 
        cardinfo0_.upload_flag , 
        cardinfo0_.user_no , 
        cardinfo0_.user_pin   
    from 
        card_info cardinfo0_  
    left outer join 
        business_unit_info businessun1_  
            on cardinfo0_.business_unit_info_id=businessun1_.id  
    left outer join 
        business_unit_info businessun2_  
            on cardinfo0_.bu_info_created_id=businessun2_.id  
    where 
        businessun1_.id= '{0}'
        and businessun2_.id<> '{1}'
    order by 
        cardinfo0_.last_modified asc 
", buid, originalBuId)).ToListAsync();
                    foreach (var card in dbCardInfo)
                    {
                        if (card.Holder != "已注销卡" && (card.LastModified != null && card.LastModified <= lastModified))
                        {
                            changeHistoryResponse.CardInfo.Add(card);
                        }
                    }


                    var dbAccountInfo = await _AccountingContext.GetRepository<AccountInfo>().FromSql(string.Format(@"
select
        accountinf0_.id,
        accountinf0_.account_id,
        accountinf0_.account_info_id,
        accountinf0_.account_no,
        accountinf0_.account_pin,
        accountinf0_.account_state,
        accountinf0_.account_type_id,
        accountinf0_.acct_sno,
        accountinf0_.acct_type,
        accountinf0_.address,
        accountinf0_.amount_limit,
        accountinf0_.balance,
        accountinf0_.belong_to,
        accountinf0_.business_unit_info_id,
        accountinf0_.bu_info_created_id,
        accountinf0_.card_class,
        accountinf0_.card_type,
        accountinf0_.cash,
        accountinf0_.certf_no,
        accountinf0_.certf_type,
        accountinf0_.creation_date,
        accountinf0_.daily_amount_limit,
        accountinf0_.discount_type,
        accountinf0_.enable_sms,
        accountinf0_.expiration_date,
        accountinf0_.fuel_no,
        accountinf0_.gid,
        accountinf0_.gas_liter_limit,
        accountinf0_.gift,
        accountinf0_.holder,
        accountinf0_.last_modified,
        accountinf0_.monthly_amount_limit,
        accountinf0_.offline_account_id,
        accountinf0_.offline_deposit_balance,
        accountinf0_.offline_phone_no,
        accountinf0_.operator_no,
        accountinf0_.physical_card_user_info,
        accountinf0_.pin_try_limit,
        accountinf0_.recharge_total,
        accountinf0_.sno,
        accountinf0_.t_mac,
        accountinf0_.upload_flag,
        accountinf0_.user_id,
        accountinf0_.user_info_id,
        accountinf0_.validation_date 
    from
        account_info accountinf0_ 
    left outer join
        business_unit_info businessun1_ 
            on accountinf0_.business_unit_info_id=businessun1_.id 
    left outer join
        business_unit_info businessun2_ 
            on accountinf0_.bu_info_created_id=businessun2_.id 
    where
        businessun1_.id= '{0}'
        and businessun2_.id<> '{1}'
    order by
        accountinf0_.last_modified asc
", buid, originalBuId)).ToListAsync();
                    foreach (var accountInfo in dbAccountInfo)
                    {
                        if ((accountInfo.BelongTo != null && accountInfo.BelongTo != "已注销账户") && (accountInfo.LastModified != null && accountInfo.LastModified <= lastModified))
                        {
                            changeHistoryResponse.AccountInfo.Add(accountInfo);
                        }
                    }

                    var dbBlackCardInfo = await _AccountingContext.GetRepository<BlackCardInfo>().FromSql(string.Format(@"
                  select
        blackcardi0_.id,
        blackcardi0_.acct_gid,
        blackcardi0_.acct_id,
        blackcardi0_.black_card_type,
        blackcardi0_.black_date,
        blackcardi0_.bu_info_id,
        blackcardi0_.bu_info_created_id,
        blackcardi0_.card_no,
        blackcardi0_.card_type,
        blackcardi0_.discount_no,
        blackcardi0_.gid,
        blackcardi0_.is_deleted,
        blackcardi0_.last_modified,
        blackcardi0_.reason,
        blackcardi0_.upload_flag
    from
        black_card_info blackcardi0_ 
    left outer join
        business_unit_info businessun1_ 
            on blackcardi0_.bu_info_id=businessun1_.id 
    left outer join
        business_unit_info businessun2_ 
            on blackcardi0_.bu_info_created_id=businessun2_.id 
    where
        businessun1_.id= '{0}'
        and businessun2_.id<> '{1}'
    order by
        blackcardi0_.last_modified asc
", buid, originalBuId)).ToListAsync();
                    foreach (var black in dbBlackCardInfo)
                    {
                        if (black.LastModified <= lastModified)
                        {
                            changeHistoryResponse.BlackCardInfo.Add(black);
                        }
                    }

                    var dbGrayInfo = await _AccountingContext.GetRepository<GrayInfo>().FromSql(string.Format(@"
                 select
        grayinfo0_.id,
        grayinfo0_.bu_info_id,
        grayinfo0_.bu_info_created_id,
        grayinfo0_.card_balance,
        grayinfo0_.card_no,
        grayinfo0_.comm_id,
        grayinfo0_.ctc,
        grayinfo0_.discount_no,
        grayinfo0_.end_pump,
        grayinfo0_.gid,
        grayinfo0_.gmac,
        grayinfo0_.is_deleted,
        grayinfo0_.last_modified,
        grayinfo0_.money,
        grayinfo0_.nozzle_no,
        grayinfo0_.pay_terminal_id,
        grayinfo0_.paymode_id,
        grayinfo0_.price,
        grayinfo0_.psam_asn,
        grayinfo0_.psam_tac,
        grayinfo0_.psam_tid,
        grayinfo0_.psam_ttc,
        grayinfo0_.pump_no,
        grayinfo0_.pump_type,
        grayinfo0_.real_money,
        grayinfo0_.sno,
        grayinfo0_.sequence_no,
        grayinfo0_.tac,
        grayinfo0_.tmac,
        grayinfo0_.trd_type,
        grayinfo0_.ttc,
        grayinfo0_.ttc_time,
        grayinfo0_.ttc_time_end,
        grayinfo0_.upload_flag,
        grayinfo0_.volume 
    from
        gray_info grayinfo0_ 
    left outer join
        business_unit_info businessun1_ 
            on grayinfo0_.bu_info_id=businessun1_.id 
    left outer join
        business_unit_info businessun2_ 
            on grayinfo0_.bu_info_created_id=businessun2_.id 
    where
        businessun1_.id= '{0}'
        and businessun2_.id<> '{1}'
    order by
        grayinfo0_.last_modified asc

", buid, originalBuId)).ToListAsync();
                    foreach (var grayInfo in dbGrayInfo)
                    {
                        if (grayInfo.LastModified <= lastModified)
                        {
                            changeHistoryResponse.GrayInfo.Add(grayInfo);
                        }
                    }

                    if (ihostSyncRepLost)
                    {
                        var dbRepLossInfo = await _AccountingContext.GetRepository<CardRepLossInfo>().FromSql(string.Format(@"
select
        cardreplos0_.id,
        cardreplos0_.bu_info_id,
        cardreplos0_.bu_info_created_id,
        cardreplos0_.card_no,
        cardreplos0_.gid,
        cardreplos0_.last_modified,
        cardreplos0_.loss_time,
        cardreplos0_.operation_type,
        cardreplos0_.operator_no,
        cardreplos0_.reason,
        cardreplos0_.sno 
    from
        card_rep_loss_info cardreplos0_ 
    left outer join
        business_unit_info businessun1_ 
            on cardreplos0_.bu_info_id=businessun1_.id 
    left outer join
        business_unit_info businessun2_ 
            on cardreplos0_.bu_info_created_id=businessun2_.id 
    where
        businessun1_.id= '{0}'
        and businessun2_.id<> '{1}'
    order by
        cardreplos0_.last_modified asc
", buid, originalBuId)).ToListAsync();
                        foreach (var lossInfo in dbRepLossInfo)
                        {
                            if (lossInfo.LastModified <= lastModified)
                            {
                                changeHistoryResponse.cardRepLossInfos.Add(lossInfo);
                            }
                        }
                    }

                }
                else
                {
                    var dbCardInfo = _AccountingContext.GetRepository<CardInfo>().GetAll().Where(a => a.BusinessUnitInfoId == buid).ToList();
                    //var dbCardInfo = await _AccountingContext.GetRepository<CardInfo>().FromSql(sql).ToListAsync();

                    foreach (var card in dbCardInfo)
                    {
                        if (card.Holder != "已注销卡" && (card.LastModified != null && card.LastModified <= lastModified))
                        {
                            changeHistoryResponse.CardInfo.Add(card);
                        }
                    }

                    //                    var dbAccountInfo = await _AccountingContext.GetRepository<AccountInfo>().FromSql(string.Format(@"
                    //                 select accountinf0_.*
                    //    from
                    //        account_info accountinf0_ 
                    //    left outer join
                    //        business_unit_info businessun1_ 
                    //            on accountinf0_.business_unit_info_id=businessun1_.id 
                    //    where
                    //        businessun1_.id= '{0}'
                    //    order by
                    //        accountinf0_.last_modified asc
                    //", buid)).ToListAsync();

                    var dbAccountInfo = _AccountingContext.GetRepository<AccountInfo>().GetAll().Where(a => a.BusinessUnitInfoId == buid).ToList();
                    foreach (var accountInfo in dbAccountInfo)
                    {
                        if ((accountInfo.BelongTo != null && accountInfo.BelongTo != "已注销账户") && (accountInfo.LastModified != null && accountInfo.LastModified <= lastModified))
                        {
                            changeHistoryResponse.AccountInfo.Add(accountInfo);
                        }
                    }

                    var dbBlackCardInfo = _AccountingContext.GetRepository<BlackCardInfo>().GetAll().Where(a => a.BuInfoId == buid).ToList();
                    //                    var dbBlackCardInfo = await _AccountingContext.GetRepository<BlackCardInfo>().FromSql(string.Format(@"
                    //                select
                    //        blackcardi0_.id,
                    //        blackcardi0_.acct_gid,
                    //        blackcardi0_.acct_id,
                    //        blackcardi0_.black_card_type,
                    //        blackcardi0_.black_date,
                    //        blackcardi0_.bu_info_id,
                    //        blackcardi0_.bu_info_created_id,
                    //        blackcardi0_.card_no,
                    //        blackcardi0_.card_type,
                    //        blackcardi0_.discount_no,
                    //        blackcardi0_.gid,
                    //        blackcardi0_.is_deleted,
                    //        blackcardi0_.last_modified,
                    //        blackcardi0_.reason,
                    //        blackcardi0_.upload_flag 
                    //    from
                    //        black_card_info blackcardi0_ 
                    //    left outer join
                    //        business_unit_info businessun1_ 
                    //            on blackcardi0_.bu_info_id=businessun1_.id 
                    //    where
                    //        businessun1_.id= '{0}'
                    //    order by
                    //        blackcardi0_.last_modified asc
                    //", buid)).ToListAsync();
                    foreach (var black in dbBlackCardInfo)
                    {
                        if (black.LastModified <= lastModified)
                        {
                            changeHistoryResponse.BlackCardInfo.Add(black);
                        }
                    }
                    var dbGrayInfo = _AccountingContext.GetRepository<GrayInfo>().GetAll().Where(a => a.BuInfoId == buid).ToList();
                    //                    var dbGrayInfo = await _AccountingContext.GetRepository<GrayInfo>().FromSql(string.Format(@"
                    //                   select
                    //        grayinfo0_.id,
                    //        grayinfo0_.bu_info_id,
                    //        grayinfo0_.bu_info_created_id,
                    //        grayinfo0_.card_balance,
                    //        grayinfo0_.card_no,
                    //        grayinfo0_.comm_id,
                    //        grayinfo0_.ctc,
                    //        grayinfo0_.discount_no,
                    //        grayinfo0_.end_pump,
                    //        grayinfo0_.gid,
                    //        grayinfo0_.gmac,
                    //        grayinfo0_.is_deleted,
                    //        grayinfo0_.last_modified,
                    //        grayinfo0_.money,
                    //        grayinfo0_.nozzle_no,
                    //        grayinfo0_.pay_terminal_id,
                    //        grayinfo0_.paymode_id,
                    //        grayinfo0_.price,
                    //        grayinfo0_.psam_asn,
                    //        grayinfo0_.psam_tac,
                    //        grayinfo0_.psam_tid,
                    //        grayinfo0_.psam_ttc,
                    //        grayinfo0_.pump_no,
                    //        grayinfo0_.pump_type,
                    //        grayinfo0_.real_money,
                    //        grayinfo0_.sno,
                    //        grayinfo0_.sequence_no,
                    //        grayinfo0_.tac,
                    //        grayinfo0_.tmac,
                    //        grayinfo0_.trd_type,
                    //        grayinfo0_.ttc,
                    //        grayinfo0_.ttc_time,
                    //        grayinfo0_.ttc_time_end,
                    //        grayinfo0_.upload_flag,
                    //        grayinfo0_.volume
                    //    from
                    //        gray_info grayinfo0_ 
                    //    left outer join
                    //        business_unit_info businessun1_ 
                    //            on grayinfo0_.bu_info_id=businessun1_.id 
                    //    where
                    //        businessun1_.id= '{0}'
                    //    order by
                    //        grayinfo0_.last_modified asc
                    //", buid)).ToListAsync();
                    foreach (var grayInfo in dbGrayInfo)
                    {
                        if (grayInfo.LastModified <= lastModified)
                        {
                            changeHistoryResponse.GrayInfo.Add(grayInfo);
                        }
                    }

                    if (ihostSyncRepLost)
                    {
                        var dbRepLossInfo = _AccountingContext.GetRepository<CardRepLossInfo>().GetAll().Where(a => a.BuInfoId == buid).ToList();
                        //                        var dbRepLossInfo = await _AccountingContext.GetRepository<CardRepLossInfo>().FromSql(string.Format(@"
                        //select
                        //        cardreplos0_.id,
                        //        cardreplos0_.bu_info_id,
                        //        cardreplos0_.bu_info_created_id,
                        //        cardreplos0_.card_no,
                        //        cardreplos0_.gid,
                        //        cardreplos0_.last_modified,
                        //        cardreplos0_.loss_time,
                        //        cardreplos0_.operation_type,
                        //        cardreplos0_.operator_no,
                        //        cardreplos0_.reason,
                        //        cardreplos0_.sno 
                        //    from
                        //        card_rep_loss_info cardreplos0_ 
                        //    left outer join
                        //        business_unit_info businessun1_ 
                        //            on cardreplos0_.bu_info_id=businessun1_.id 
                        //    where
                        //        businessun1_.id= '{0}'
                        //    order by
                        //        cardreplos0_.last_modified asc
                        //", buid)).ToListAsync();
                        foreach (var lossInfo in dbRepLossInfo)
                        {
                            if (lossInfo.LastModified <= lastModified)
                            {
                                changeHistoryResponse.cardRepLossInfos.Add(lossInfo);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }
            return changeHistoryResponse;
        }
        public Task getRecordsGreaterThanVersionNo(Guid? buid, Guid? originalBuId, long fromVersionNo, long toVersionNo, bool excludingCurrentBu)
        {
            List<ChangeHistory> changeHistoryResponse = new List<ChangeHistory>();
            ChangeHistoryResponse response = new ChangeHistoryResponse();
            if (excludingCurrentBu)
            {
                changeHistoryResponse = _AccountingContext.GetRepository<ChangeHistory>().FromSql(string.Format(@"
                select 
        changehist0_.id, 
        changehist0_.bu_id , 
        changehist0_.bu_info_created_id , 
        changehist0_.last_modified , 
        changehist0_.record_id , 
        changehist0_.table_name  
    from 
        change_history changehist0_  
    where 
        changehist0_.bu_id= '{0}'
        and changehist0_.bu_info_created_id <> '{1}'
        and changehist0_.id>  '{2}'
        and changehist0_.id<=  '{3}' 
    order by 
        changehist0_.id asc 
", buid, originalBuId, fromVersionNo, toVersionNo)).ToListAsync().Result;
            }
            else
            {
                changeHistoryResponse = _AccountingContext.GetRepository<ChangeHistory>().FromSql(string.Format(@"
                 select 
        changehist0_.id , 
        changehist0_.bu_id, 
        changehist0_.bu_info_created_id , 
        changehist0_.last_modified , 
        changehist0_.record_id , 
        changehist0_.table_name   
    from 
        change_history changehist0_  
    where 
        changehist0_.bu_id='{0}' 
        and changehist0_.id>'{1}' 
        and changehist0_.id<='{2}' 
    order by 
        changehist0_.id asc 
", buid, fromVersionNo, toVersionNo)).ToListAsync().Result;
            }
            var changes = removeDuplicatedRecords(changeHistoryResponse);
            foreach (var changeHistory in changes)
            {
                var tableName = changeHistory.TableName;
                var recordId = changeHistory.RecordId;

                if (tableName == 0)//卡
                {
                    var card = _AccountingContext.GetRepository<CardInfo>().Find(recordId);
                    if (card != null)
                    {
                        if (card.Holder != "已注销卡")
                        {
                            response.CardInfo.Add(card);
                        }
                    }
                }
                else if (tableName == 1)//ACCOUNT_INFO
                {
                    var account = _AccountingContext.GetRepository<AccountInfo>().Find(recordId);
                    if (account != null)
                    {
                        if (account.BelongTo != "已注销账户")
                        {
                            response.AccountInfo.Add(account);
                        }
                    }
                }
                else if (tableName == 2)
                {
                    var black = _AccountingContext.GetRepository<BlackCardInfo>().Find(recordId);
                    if (black != null)
                    {
                        response.BlackCardInfo.Add(black);
                    }
                }
                else if (tableName == 3)
                {
                    var gray = _AccountingContext.GetRepository<GrayInfo>().Find(recordId);
                    if (gray != null)
                    {
                        response.GrayInfo.Add(gray);
                    }
                }
                else if (tableName == 4)
                {
                    var loss = _AccountingContext.GetRepository<CardRepLossInfo>().Find(recordId);
                    if (loss != null)
                    {
                        response.cardRepLossInfos.Add(loss);
                    }
                }
                else
                {
                    if (tableName == -2 || tableName == -1)
                    {
                        MS.WebCore.Logger.Logger.WriteLog
                            ("Ignored table typ：" + tableName);
                    }
                    else
                    {
                        MS.WebCore.Logger.Logger.WriteLog("Unexpected table type " + tableName);
                    }
                }
            }
            return null;
        }
        public List<ChangeHistory> removeDuplicatedRecords(List<ChangeHistory> changeHistories)
        {
            var changes = new List<ChangeHistory>();
            var cardAndAccountList = new List<ChangeHistory>();
            var otherInfoList = new List<ChangeHistory>();
            foreach (var change in changeHistories)
            {
                if (change.TableName == 1 || change.TableName == 0)
                {
                    cardAndAccountList.Add(change);
                }
                else
                {
                    otherInfoList.Add(change);
                }
            }
            cardAndAccountList = RemoveDuplicatesAndPreserveOrder(cardAndAccountList);
            changes.AddRange(cardAndAccountList);
            changes.AddRange(otherInfoList);
            return changeHistories;
        }
        static List<ChangeHistory> RemoveDuplicatesAndPreserveOrder(List<ChangeHistory> sourceList)
        {
            HashSet<ChangeHistory> uniqueSet = new HashSet<ChangeHistory>(sourceList);

            // 使用 LINQ 的 OrderBy 方法按原列表中元素的出现顺序排列
            return sourceList.OrderBy(item => sourceList.IndexOf(item))
                             .Where(item => uniqueSet.Contains(item))
                             .ToList();
        }
        public Task ClearhashValues(string key)
        {
            List<string> hashValues = redisExample.GetHashKeysByPattern(key);//EmployeeCard:*
            foreach (var value in hashValues)
            {
                redisExample.DeleteData(value);
            }
            return Task.CompletedTask; 
        }
        public async Task AddCarRedisAsync()
        {
            DateTime now = DateTime.Now;

            DateTime firstDayOfPreviousMonth = now.AddMonths(-1).Date.AddDays(-(now.Day - 1));

            string date = firstDayOfPreviousMonth.ToString("yyyy-MM-dd");
            List<KeyValuePair<string, string>> hashValues = redisExample.GetListValues("business_unit_info");
            if (hashValues.Count > 0)
            {
                foreach (var kvp in hashValues)
                {
                  await  AddEmployeeCardMonthlySummaryToRedisAsync(kvp.Key, date, "0");
                  await AddEmployeeCardMonthlySummaryToRedisAsync(kvp.Key, date, "1");
                }
            }
        }
        public void Getdate(string buid, string date, string Car)
        {
            redisExample.AddToHash(buid, date, "1");
        }
        public async Task addredis(string buid)
        {
            List<KeyValuePair<string, string>> hashValues = redisExample.GetListValues(buid);
            if (hashValues.Count > 0)
            {
                List<DateTime> dates = new List<DateTime>();
                foreach (var kvp in hashValues)
                {
                    DateTime dateTime1 = DateTime.Parse(kvp.Key);
                    dates.Add(dateTime1);
                }
                string date = dates.Max().ToString("yyyy-MM-dd");//
                string maxDate = string.Empty;//
                string value = hashValues.FirstOrDefault(x => x.Key == date).Value;


                await AddEmployeeCardMonthlySummaryToRedisAsync(buid, date, "0");
                await AddEmployeeCardMonthlySummaryToRedisAsync(buid, date, "1");
                redisExample.AddToHash(buid, dates.Max().AddMonths(1).ToString("yyyy-MM-dd"), "2");
            }
        }
        public Task AddEmployeeCardMonthlySummaryToRedisAsync(string buid, string date, string Car)
        {
            int cartype = GetCarType(buid, Car);
            // AddgroupedAccountIdTotal(buid, date);
            AddCardSummary(buid, date, Car);
            string keyname = Car == "0" ? "UserCard" : "EmployeeCard";
            DateTime dateTime = DateTime.Parse(date);
            DateTime firstDayOfNextMonth = dateTime.AddMonths(1).AddDays(-dateTime.Day);
            var enddate = firstDayOfNextMonth.ToString("yyyy-MM-dd 23:59:59");
            string sql = string.Format(@"
     
                    SELECT ai.belong_to, trx.account_id, trx.card_no, ci.holder, count(*) as trx_count, sum(trx.volume) as volume, sum(trx.amount) as amount,
            ci.card_type, ci.creation_date as card_creation_date, ci.card_status, 
            (array_agg(ai.account_state))[1] as account_status,  
            (array_agg(ai.creation_date))[1] as creation_date, 
            (array_agg(ai.balance ORDER BY trx.transaction_time DESC))[1] as account_balance, 
            (array_agg(ai.recharge_total ORDER BY trx.transaction_time DESC))[1] as recharge_total, 
            (array_agg(ai.acct_type))[1] as account_type, 
            (array_agg(ci.balance ORDER BY trx.transaction_time DESC))[1] as card_balance,
            (array_agg(ai.offline_deposit_balance ORDER BY trx.transaction_time DESC))[1] as account_deposite_balance,
            (array_agg(ci.deposit_balance ORDER BY trx.transaction_time DESC))[1] as card_deposite_balance, 
            (array_agg(ci.recharge_total ORDER BY trx.transaction_time DESC))[1] as card_recharge_total,0 as card_balance_update
            FROM public.offline_transaction_info trx 
            LEFT JOIN public.account_info ai ON ai.id = trx.account_info_id 
            LEFT JOIN public.card_info ci ON ci.id = trx.card_info_id 
            WHERE trx.business_unit_info_id IN ('{0}')
           AND '{1}' <= trx.transaction_time AND trx.transaction_time <= '{2}'
            AND ci.holder is not null 
            AND ci.activation_date is not null 
             AND ci.card_type IN ({3})
            AND ((trx.transaction_type = 10 AND trx.sub_transaction_type IN (0, 1)) OR trx.transaction_type = 1) 
            GROUP BY trx.account_id, trx.card_no, ai.belong_to, ci.holder, ci.card_type, ci.creation_date, ci.card_status
            ORDER BY trx.account_id DESC 
", buid, date, enddate, cartype);

            var results = _AccountingContext.DbContext.acctDtos
               .FromSqlRaw(sql)
                 .ToList();
            string sdate = DateTime.Parse(date).ToString("yyyy-MM-dd");


            var account_ids = results
        .Select(p => p.account_id)
        .Distinct()
        .ToList();
            string sqljoin = "";

            const int chunkSize = 100;

            // 存储查询结果的列表  
            List<AccountRechargeTotal> allAccountRecharges = new List<AccountRechargeTotal>();

            // 计算总块数  
            int totalChunks = (account_ids.Count + chunkSize - 1) / chunkSize;
            for (int i = 0; i < totalChunks; i++)
            {
                int startIndex = i * chunkSize;
                int endIndex = Math.Min(startIndex + chunkSize, account_ids.Count);

                List<string> chunkAccountIds = account_ids.GetRange(startIndex, endIndex - startIndex);

                string sqlJoin = string.Join(",", chunkAccountIds.Select(id => string.Format("'{0}'", id)));

                sql = string.Format(@"
                            SELECT ci.account_id, sum(trx.amount) as amount FROM public.offline_transaction_info trx 
                            LEFT JOIN public.card_info ci ON trx.card_info_id = ci.id 
                            LEFT JOIN public.account_info ai ON ai.id = trx.account_info_id 
                             WHERE trx.business_unit_info_id IN ('{0}')
                            AND ci.account_id IN ({1})
                           AND '{2}' <= trx.transaction_time AND trx.transaction_time <= '{3}'
                            AND trx.transaction_type IN (0, 5, 7, 8) 
                            AND trx.recharge_type is not null 
                            GROUP BY ci.account_id
                ", buid, sqljoin, date, enddate);


                sql = string.Format(sql, buid, sqlJoin); 

                var chunkAccountRecharges = _AccountingContext.DbContext.accountRechargeTotals
                    .FromSqlRaw(sql)
                    .ToList();

                allAccountRecharges.AddRange(chunkAccountRecharges);
            }
            #region

            //            for (var i = 0; i < account_ids.Count(); i++)
            //            {
            //                sqljoin += string.Format(@"'{0}',", account_ids[i]);
            //            }
            //            if (!string.IsNullOrEmpty(sqljoin))
            //            {
            //                sqljoin = sqljoin.Substring(0, sqljoin.Length - 1);
            //            }
            //            sql = string.Format(@"
            //            SELECT ci.account_id, sum(trx.amount) as amount FROM public.offline_transaction_info trx 
            //            LEFT JOIN public.card_info ci ON trx.card_info_id = ci.id 
            //            LEFT JOIN public.account_info ai ON ai.id = trx.account_info_id 
            //             WHERE trx.business_unit_info_id IN ('{0}')
            //            AND ci.account_id IN ({1})
            //           AND '{2}' <= trx.transaction_time AND trx.transaction_time <= '{3}'
            //            AND trx.transaction_type IN (0, 5, 7, 8) 
            //            AND trx.recharge_type is not null 
            //            GROUP BY ci.account_id
            //", buid, sqljoin, date, enddate);
            //            var accountRecharge = _AccountingContext.DbContext.accountRechargeTotals
            //              .FromSqlRaw(sql)
            //                .ToList();

            #endregion

            #region

            var car_ids = results
.Select(p => p.card_no)
.Distinct()
.ToList();
            //            sqljoin = "";
            //            for (var i = 0; i < car_ids.Count(); i++)
            //            {
            //                sqljoin += string.Format(@"'{0}',", car_ids[i]);
            //            }
            //            if (!string.IsNullOrEmpty(sqljoin))
            //            {
            //                sqljoin = sqljoin.Substring(0, sqljoin.Length - 1);
            //            }
            //            sql = string.Format(@"
            //    SELECT trx.card_no as account_id, (array_agg(trx.card_balance ORDER BY trx.transaction_time DESC))[1] as amount 
            //            FROM public.offline_transaction_info trx 
            //            WHERE trx.business_unit_info_id IN ('{0}')
            //            AND trx.card_no IN ({1})
            //             AND '{2}' <= trx.transaction_time AND trx.transaction_time <= '{3}'
            //            AND trx.transaction_type IN (1, 2, 3, 4, 7, 8, 10) 
            //            GROUP BY trx.card_no
            //", buid, sqljoin, date, enddate);
            //            var carRecharge = _AccountingContext.DbContext.accountRechargeTotals
            //          .FromSqlRaw(sql)
            //            .ToList();
            #endregion


            List<AccountRechargeTotal> allCarRecharges = new List<AccountRechargeTotal>(); // 替换YourResultType为实际类型  

             totalChunks = (car_ids.Count + chunkSize - 1) / chunkSize;

            for (int i = 0; i < totalChunks; i++)
            {
                int startIndex = i * chunkSize;
                int endIndex = Math.Min(startIndex + chunkSize, car_ids.Count);

                List<string> chunkCardIds = car_ids.GetRange(startIndex, endIndex - startIndex);
                string sqlJoin = string.Join(",", chunkCardIds.Select(id => string.Format("'{0}'", id)));

                 sql = @"  
        SELECT trx.card_no as account_id, (array_agg(trx.card_balance ORDER BY trx.transaction_time DESC))[1] as amount   
        FROM public.offline_transaction_info trx   
        WHERE trx.business_unit_info_id = @BuId  
        AND trx.card_no IN ({0})  
        AND trx.transaction_time BETWEEN @StartDate AND @EndDate  
        AND trx.transaction_type IN (1, 2, 3, 4, 7, 8, 10)   
        GROUP BY trx.card_no;  
    ";

                var parameters = new SqlParameter[]
                {
        new SqlParameter("@BuId", buid),
        new SqlParameter("@StartDate", date),
        new SqlParameter("@EndDate", enddate)
                };

                var chunkCarRecharges = _AccountingContext.DbContext.accountRechargeTotals
          .FromSqlRaw(sql)
            .ToList();

                allCarRecharges.AddRange(chunkCarRecharges);
            }


            //"149f3efa-28a0-4368-af6d-af65ca255ef0"   2020-09-15 14:17:22
            for (var i = 0; i < results.Count(); i++)
            {
                string key = keyname + ":" + buid + ":" + results[i].card_no + ":" + results[i].belong_to;//key
                var hashkey = redisExample.HashKeyExists(key, date);
                JsonSerializerSettings settings = new JsonSerializerSettings
                {
                    ContractResolver = new CustomContractResolver(new[] { "trx_count", "volume", "amount" })
                };
                long? Totals = 0;
                if (allAccountRecharges != null && allAccountRecharges.Count > 0)
                {
                    Totals = allAccountRecharges.Where(a => a.account_id == results[i].account_id).FirstOrDefault()?.amount;
                }
                results[i].recharge_total = Totals;

                long? card_balance_update = 0;
                if (allCarRecharges != null && allCarRecharges.Count > 0)
                {
                    card_balance_update = allCarRecharges.Where(a => a.account_id == results[i].card_no).FirstOrDefault()?.amount;
                }
                results[i].card_balance_update = card_balance_update;

                string resultsjson = JsonConvert.SerializeObject(results[i], settings);
                string data = JsonConvert.SerializeObject(results[i]);
                if (hashkey)
                {
                    continue;
                }

                List<KeyValuePair<string, string>> hashValues = redisExample.GetListValues(key);
                if (hashValues.Count > 0)
                {
                    List<DateTime> dates = new List<DateTime>();
                    foreach (var kvp in hashValues)
                    {
                        DateTime dateTime1 = DateTime.Parse(kvp.Key);
                        dates.Add(dateTime1);
                    }
                    string maxDate = dates.Max().ToString("yyyy-MM-dd");//
                    KeyValuePair<string, string> foundPair = hashValues.FirstOrDefault(kvp => kvp.Key == maxDate);
                    if (!string.IsNullOrEmpty(foundPair.Key))
                    {
                        var foundPairvalue = foundPair.Value;
                        OuterObject rootObject = JsonConvert.DeserializeObject<OuterObject>(foundPairvalue);
                        AcctDto acctDto = JsonConvert.DeserializeObject<AcctDto>(rootObject.data);
                        acctDto.trx_count = LongConversion(acctDto.trx_count) + LongConversion(results[i].trx_count);
                        acctDto.volume = LongConversion(acctDto.volume) + LongConversion(results[i].volume);
                        acctDto.amount = LongConversion(acctDto.amount) + LongConversion(results[i].amount);
                        acctDto.recharge_total = Totals != null && Totals != 0 ? Totals : acctDto.recharge_total;
                        acctDto.card_balance_update = card_balance_update != null && card_balance_update != 0 ? card_balance_update : acctDto.card_balance_update;
                        data = JsonConvert.SerializeObject(acctDto);
                    }
                }


                string json = JsonConvert.SerializeObject(new { data = data, update = resultsjson });
                redisExample.AddToHash(key, date, json);

            }
            return Task.CompletedTask;
        }
        public Task AddCardSummary(string buid, string date, string Car)
        {
            string keyname = Car == "0" ? "UserCardSummary" : "CardSummary";
            int cartype = GetCarType(buid, Car);
            DateTime dateTime = DateTime.Parse(date);
            DateTime firstDayOfNextMonth = dateTime.AddMonths(1).AddDays(-dateTime.Day);
            var enddate = firstDayOfNextMonth.ToString("yyyy-MM-dd 23:59:59");
            List<CardCollect> cards = new List<CardCollect>();
            #region  rechargeTotal
            ///rechargeTotal
            string sql = string.Format(@"
SELECT ai.belong_to,sum(trx.amount) as amount,0 as volume FROM public.offline_transaction_info trx
            LEFT JOIN public.card_info ci ON trx.card_info_id = ci.id
            LEFT JOIN public.account_info ai ON ai.id = trx.account_info_id 
            WHERE trx.business_unit_info_id IN ('{0}')
             AND ci.card_type IN ({3})
          AND '{1}' <= trx.transaction_time AND trx.transaction_time <= '{2}'
            AND trx.transaction_type IN (0, 5, 7, 8) 
            AND trx.recharge_type is not null
            group by ai.belong_to 
", buid, date, enddate, cartype);
            var rechargeTotalresults = _AccountingContext.DbContext.cardSummaries
               .FromSqlRaw(sql)
                 .ToList();
            for (var i = 0; i < rechargeTotalresults.Count(); i++)
            {
                CardCollect cardCollect = new CardCollect();
                cardCollect.belong_to = rechargeTotalresults[i].belong_to;
                cardCollect.rechargeTotal = LongConversion(rechargeTotalresults[i].amount);
                cards.Add(cardCollect);
            }
            #endregion

            #region trxTotal
            //trxTotal
            sql = string.Format(@"
 SELECT ai.belong_to,sum(trx.amount) as amount, sum(trx.volume) as volume FROM public.offline_transaction_info trx
            LEFT JOIN public.card_info ci ON trx.card_info_id = ci.id
            LEFT JOIN public.account_info ai ON ai.id = trx.account_info_id 
           WHERE trx.business_unit_info_id IN ('{0}')
              AND ci.card_type IN ({3})
              AND '{1}' <= trx.transaction_time AND trx.transaction_time <= '{2}'
            AND ((trx.transaction_type = 10 AND trx.sub_transaction_type IN (0, 1)) OR trx.transaction_type  = 1)
            group by ai.belong_to
", buid, date, enddate, cartype);
            var trxTotalResults = _AccountingContext.DbContext.cardSummaries
            .FromSqlRaw(sql)
              .ToList();
            for (var i = 0; i < trxTotalResults.Count(); i++)
            {
                var belong_to = trxTotalResults[i].belong_to;
                var car = cards.Where(a => a.belong_to == belong_to).FirstOrDefault();
                if (car != null)
                {
                    car.amountTotal = LongConversion(trxTotalResults[i].amount);
                    car.volumeTotal = LongConversion(trxTotalResults[i].volume);
                }
                else
                {
                    CardCollect cardCollect = new CardCollect();
                    cardCollect.belong_to = trxTotalResults[i].belong_to;
                    cardCollect.amountTotal = LongConversion(trxTotalResults[i].amount);
                    cardCollect.volumeTotal = LongConversion(trxTotalResults[i].volume);
                    cards.Add(cardCollect);
                }
            }
            #endregion

            #region  cardBalanceTotal

            //            sql = string.Format(@"
            //  SELECT ai.belong_to,(array_agg(ai.balance))[1] as amount, (array_agg(ai.offline_deposit_balance))[1] as volume FROM public.account_info ai 
            //            JOIN public.card_info ci on ci.account_info_id = ai.id 
            //            WHERE ci.bu_info_created_id IN ('{0}')
            //            AND ci.card_type IN (4)
            //            GROUP BY ai.id,ai.belong_to
            //", buid);
            //            var cardBalanceTotalResults = _AccountingContext.DbContext.cardSummaries
            //            .FromSqlRaw(sql)
            //              .ToList();
            //            for (var i = 0; i < cardBalanceTotalResults.Count(); i++)
            //            {
            //                var belong_to = cardBalanceTotalResults[i].belong_to;
            //                var car = cards.Where(a => a.belong_to == belong_to).FirstOrDefault();
            //                if (car != null)
            //                {
            //                    car.cardBalanceTotal = LongConversion(cardBalanceTotalResults[i].amount);
            //                    car.cardDepositTotal = LongConversion(cardBalanceTotalResults[i].volume);
            //                }
            //                else
            //                {
            //                    CardCollect cardCollect = new CardCollect();
            //                    cardCollect.belong_to = cardBalanceTotalResults[i].belong_to;
            //                    cardCollect.cardBalanceTotal = LongConversion(cardBalanceTotalResults[i].amount);
            //                    cardCollect.cardDepositTotal = LongConversion(cardBalanceTotalResults[i].volume);
            //                    cards.Add(cardCollect);
            //                }
            //            }
            #endregion

            #region  accountBalanceTotal

            //            sql = string.Format(@"
            //   SELECT ai.belong_to,sum(ci.balance) as amount, sum(ci.deposit_balance) as volume FROM public.card_info ci 
            //            LEFT JOIN public.account_info ai ON ai.id = ci.account_info_id 
            //            WHERE ci.bu_info_created_id  IN ('{0}')
            //            AND ci.card_type IN (4)
            //            group by ai.belong_to
            //", buid);
            //            var accountBalanceTotalResults = _AccountingContext.DbContext.cardSummaries
            //            .FromSqlRaw(sql)
            //              .ToList();
            //            for (var i = 0; i < accountBalanceTotalResults.Count(); i++)
            //            {
            //                var belong_to = accountBalanceTotalResults[i].belong_to;
            //                var car = cards.Where(a => a.belong_to == belong_to).FirstOrDefault();
            //                if (car != null)
            //                {
            //                    car.balanceTotal = LongConversion(accountBalanceTotalResults[i].amount);
            //                    car.accountDepositTotal = LongConversion(accountBalanceTotalResults[i].volume);
            //                }
            //                else
            //                {
            //                    CardCollect cardCollect = new CardCollect();
            //                    cardCollect.belong_to = accountBalanceTotalResults[i].belong_to;
            //                    cardCollect.balanceTotal = LongConversion(cardBalanceTotalResults[i].amount);
            //                    cardCollect.accountDepositTotal = LongConversion(cardBalanceTotalResults[i].volume);
            //                    cards.Add(cardCollect);
            //                }
            //            }
            #endregion


            #region  cardTotal

            //            sql = string.Format(@"
            // SELECT ai.belong_to,count(ci.id) amount,0 as volume FROM public.account_info ai 
            //            JOIN public.card_info ci on ci.account_info_id = ai.id 
            //            WHERE ci.bu_info_created_id IN ('{0}')
            //            AND ci.card_type IN (4)
            //            group by ai.belong_to
            //", buid);
            //            var cardTotalResults = _AccountingContext.DbContext.cardSummaries
            //            .FromSqlRaw(sql)
            //              .ToList();
            //            for (var i = 0; i < cardTotalResults.Count(); i++)
            //            {
            //                var belong_to = cardTotalResults[i].belong_to;
            //                var car = cards.Where(a => a.belong_to == belong_to).FirstOrDefault();
            //                if (car != null)
            //                {
            //                    car.cardTotal = LongConversion(cardTotalResults[i].amount);
            //                }
            //                else
            //                {
            //                    CardCollect cardCollect = new CardCollect();
            //                    cardCollect.belong_to = cardTotalResults[i].belong_to;
            //                    cardCollect.cardTotal = LongConversion(cardTotalResults[i].amount);
            //                    cards.Add(cardCollect);
            //                }
            //            }
            #endregion

            foreach (var cardCollect in cards)
            {
                string key = keyname + ":" + buid + ":" + cardCollect.belong_to;//key
                var hashkey = redisExample.HashKeyExists(key, date);
                string data = JsonConvert.SerializeObject(cardCollect);
                if (hashkey)
                {
                    continue;
                }

                List<KeyValuePair<string, string>> hashValues = redisExample.GetListValues(key);
                if (hashValues.Count > 0)
                {
                    List<DateTime> dates = new List<DateTime>();
                    foreach (var kvp in hashValues)
                    {
                        DateTime dateTime1 = DateTime.Parse(kvp.Key);
                        dates.Add(dateTime1);
                    }
                    string maxDate = dates.Max().ToString("yyyy-MM-dd");//
                    KeyValuePair<string, string> foundPair = hashValues.FirstOrDefault(kvp => kvp.Key == maxDate);
                    if (!string.IsNullOrEmpty(foundPair.Key))
                    {
                        var foundPairvalue = foundPair.Value;
                        Rootobject rootObject = JsonConvert.DeserializeObject<Rootobject>(foundPairvalue);

                        // 反序列化内层JSON字符串
                        CardCollect cardjson = JsonConvert.DeserializeObject<CardCollect>(rootObject.data);
                        cardjson.belong_to = cardCollect.belong_to;
                        //rootObject.accountBalanceTotal = LongConversion(rootObject.accountBalanceTotal) + LongConversion(cardCollect.accountBalanceTotal);
                        long amountTotal = (LongConversion(cardjson.amountTotal) + LongConversion(cardCollect.amountTotal));
                        cardjson.amountTotal = amountTotal;//
                        long volumeTotal = (LongConversion(cardjson.volumeTotal) + LongConversion(cardCollect.volumeTotal));
                        cardjson.volumeTotal = volumeTotal;//
                        long rechargeTotal = (LongConversion(cardjson.rechargeTotal) + LongConversion(cardCollect.rechargeTotal));
                        cardjson.rechargeTotal = rechargeTotal;//
                        //rootObject.accountDepositTotal = LongConversion(rootObject.accountDepositTotal )+ LongConversion(cardCollect.accountDepositTotal);
                        //rootObject.cardBalanceTotal = LongConversion(rootObject.cardBalanceTotal) + LongConversion(cardCollect.cardBalanceTotal);
                        //rootObject.cardDepositTotal = LongConversion(rootObject.cardDepositTotal )+ LongConversion(cardCollect.cardDepositTotal);
                        //rootObject.balanceTotal = LongConversion(rootObject.balanceTotal) + LongConversion(cardCollect.balanceTotal);
                        //rootObject.cardTotal = LongConversion(rootObject.cardTotal) + LongConversion(cardCollect.cardTotal);
                        data = JsonConvert.SerializeObject(cardjson);
                    }
                }
                string json = JsonConvert.SerializeObject(new { data = data });
                redisExample.AddToHash(key, date, json);
            }
            //string key = "CardSummary:" + buid + ":" + rechargeTotalresults[i].belong_to;//key
            return Task.CompletedTask;
        }
        public Task AddgroupedAccountIdTotal(string buid, string date)
        {
            DateTime dateTime = DateTime.Parse(date);
            DateTime firstDayOfNextMonth = dateTime.AddMonths(1).AddDays(-dateTime.Day);
            var enddate = firstDayOfNextMonth.ToString("yyyy-MM-dd 23:59:59");
            List<GroupedAccountIdTotal> cards = new List<GroupedAccountIdTotal>();
            #region  rechargeTotal
            ///rechargeTotal
            string sql = string.Format(@"
SELECT subquery.belong_to,subquery.accountId, count(*) count from (SELECT trx.account_id as accountId ,ai.belong_to
            FROM public.offline_transaction_info trx
            LEFT JOIN public.account_info ai ON ai.id = trx.account_info_id 
            LEFT JOIN public.card_info ci ON ci.id = trx.card_info_id
            WHERE trx.business_unit_info_id IN ('{0}')
            AND '{1}' <= trx.transaction_time AND trx.transaction_time <= '{2}'
            AND ci.holder is not null 
            AND ci.activation_date is not null 
            AND ((trx.transaction_type = 10 AND trx.sub_transaction_type IN (0, 1)) OR trx.transaction_type  = 1)
            AND ci.card_type IN (4)
            GROUP BY trx.account_id, trx.card_no,ai.belong_to) as subquery 
            GROUP BY subquery.accountId ,subquery.belong_to
            ORDER BY subquery.accountId desc
", buid, date, enddate);
            var rechargeTotalresults = _AccountingContext.DbContext.groupedAccountIdTotals
               .FromSqlRaw(sql)
                 .ToList();
            for (var i = 0; i < rechargeTotalresults.Count(); i++)
            {
                GroupedAccountIdTotal cardCollect = new GroupedAccountIdTotal();
                cardCollect.belong_to = rechargeTotalresults[i].belong_to;
                cardCollect.accountId = rechargeTotalresults[i].accountId;
                cardCollect.count = rechargeTotalresults[i].count;
                cards.Add(cardCollect);
            }

            foreach (var cardCollect in cards)
            {
                string key = "Account:" + buid + ":" + cardCollect.belong_to;//key
                var hashkey = redisExample.HashKeyExists(key, date);
                string data = JsonConvert.SerializeObject(cardCollect);
                if (hashkey)
                {
                    continue;
                }

                List<KeyValuePair<string, string>> hashValues = redisExample.GetListValues(key);
                if (hashValues.Count > 0)
                {
                    List<DateTime> dates = new List<DateTime>();
                    foreach (var kvp in hashValues)
                    {
                        DateTime dateTime1 = DateTime.Parse(kvp.Key);
                        dates.Add(dateTime1);
                    }
                    string maxDate = dates.Max().ToString("yyyy-MM-dd");//
                    KeyValuePair<string, string> foundPair = hashValues.FirstOrDefault(kvp => kvp.Key == maxDate);
                    if (!string.IsNullOrEmpty(foundPair.Key))
                    {
                        var foundPairvalue = foundPair.Value;
                        Rootobject rootObject = JsonConvert.DeserializeObject<Rootobject>(foundPairvalue);

                        // 反序列化内层JSON字符串
                        GroupedAccountIdTotal cardjson = JsonConvert.DeserializeObject<GroupedAccountIdTotal>(rootObject.data);
                        cardjson.belong_to = cardCollect.belong_to;
                        cardjson.accountId = cardCollect.accountId;
                        cardjson.count = cardjson.count + cardCollect.count;//

                        data = JsonConvert.SerializeObject(cardjson);
                    }
                }
                string json = JsonConvert.SerializeObject(new { data = data });
                redisExample.AddToHash(key, date, json);
            }
            #endregion

            return Task.CompletedTask;
        }
        public bool GetRedisKey(string key)
        {
            List<KeyValuePair<string, string>> hashValues = redisExample.GetListValues("myHash");
            return true;
        }
        public long LongConversion(long? value)
        {
            long v = value.HasValue ? value.Value : 0;
            return v;
        }


        /// <summary>
        /// 获取buid 
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<IEnumerable<string>> GetBuids()
        {
            var businessUnitInfos = await _AccountingContext.GetRepository<BusinessUnitInfo>().GetAll()
                .Where(p => !p.BuName.Contains("集团")).Where(o => !o.BuName.Contains("公司")).ToListAsync();
            if (businessUnitInfos != null && businessUnitInfos.Any())
            {
                return businessUnitInfos.Select(p => p.Id.ToString()).ToList();
            }
            return null;
        }
        /// <summary>
        /// 获取卡片类型    4 cpu卡，1感应卡
        /// car 0 - 个人卡， 1 - 员工卡
        /// </summary>
        /// <param name="buid"></param>
        /// <returns></returns>
        public int GetCarType(string buid, string Car)
        {
            int i = 4;
            if (buid == "fad023b9-333e-4a77-bea9-b07c95e5cad3"
                || buid == "0c999874-3f3e-434c-8ee7-cd57bc34c33d"
                || buid == "11902f5e-080a-4f04-9cd4-54ed139292a4"
                || buid == "3d2122d2-fb89-415a-8310-4d5646804cc0"
                  || buid == "3d2122d2-fb89-415a-8310-4d5646804cc0"
                  || buid == "f8c634fd-a231-456f-bd36-c6ee856820bc"
                  || buid == "db3b74ff-412c-45fb-9887-9b10aa179704"
                     || buid == "3fc25937-c437-41a6-9a21-0ad387315c91"
                        || buid == "df7033c4-ea67-48e3-ac4d-344ce22c6dda"
                )
            {
                if (Car == "0")
                {
                    //个人卡
                    i = 3;
                }
                else
                {
                    //员工卡
                    i = 1;
                }
            }
            else
            {
                if (Car == "0")
                {
                    //个人卡
                    i = 1;
                }
                else
                {
                    //员工卡
                    i = 4;
                }
            }
            return i;
        }
        public static List<T> MergeListsAndReturnNew<T>(List<T> list1, List<T> list2)
        {
            return list1.Concat(list2).ToList();
        }
    }
    public class CardCollect
    {
        public string belong_to { get; set; }
        public long? amountTotal { get; set; }//
        public long? volumeTotal { get; set; }//
        public long? rechargeTotal { get; set; }//
        //public long? accountBalanceTotal { get; set; }
        //public long? accountDepositTotal { get; set; }

        //public long? cardBalanceTotal { get; set; }
        //public long? cardDepositTotal { get; set; }
        //public long? balanceTotal { get; set; }
        //public long? cardTotal { get; set; }
    }

    public class Rootobject
    {
        public string data { get; set; }
    }

}
