package com.liquidnet.service.account.wallet.service.processor;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.liquidnet.service.account.common.ErrorConstants;
import com.liquidnet.service.account.common.FinConstants;
import com.liquidnet.service.account.funding.dto.FundingQueryBalanceParam;
import com.liquidnet.service.account.funding.dto.FundingQueryBalanceResult;
import com.liquidnet.service.account.funding.service.FundingAPIService;
import com.liquidnet.service.account.funding.vo.FundingAccountInfo;
import com.liquidnet.service.account.util.FinUtil;
import com.liquidnet.service.account.wallet.dto.WalletQueryResult;
import com.liquidnet.service.account.wallet.dto.base.WalletContextParam;
import com.liquidnet.service.account.wallet.entity.FinUser;
import com.liquidnet.service.account.wallet.entity.FinWallet;
import com.liquidnet.service.account.wallet.service.FinUserService;
import com.liquidnet.service.account.wallet.service.FinWalletService;
import com.liquidnet.service.account.wallet.service.WalletProcessorService;
import com.liquidnet.service.account.wallet.vo.WalletAccountInfoVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * WalletQueryProcessService.class
 *
 * @author zhanggb
 * Created by IntelliJ IDEA at 2020/10/21
 */
@Service
public class WalletAccountQueryProcessor extends WalletProcessorService {
    private static final Logger log = LoggerFactory.getLogger(WalletAccountQueryProcessor.class);
    @Autowired
    private FinWalletService walletService;
    @Autowired
    private FinUserService userService;
    @Autowired
    private FundingAPIService fundingAPIService;

    @Override
    public WalletQueryResult checkInputParams(WalletContextParam context) {
        if (null == context.getPageNum() || 0 == context.getPageNum()) {
            context.setPageNum(1);
        }
        if (null == context.getPageSize() || 0 == context.getPageSize()) {
            context.setPageSize(10);
        }
        return new WalletQueryResult();
    }

    @Override
    public WalletQueryResult checkBussinessLogic(WalletContextParam context) {
        return new WalletQueryResult();
    }

    @Override
    public WalletQueryResult doBussiness(WalletContextParam context) {
        List<WalletAccountInfoVo> walletAccountInfoVoList = new ArrayList<>();
        PageInfo<FinWallet> pageInfoTmp = null;
        List<FinWallet> walletList = null;
        if (StringUtils.isEmpty(context.getFuzzySearch())) {
            PageHelper.startPage(context.getPageNum(), context.getPageSize());
            walletList = walletService.query(BeanMap.create(context));
            pageInfoTmp = new PageInfo<>(walletList);
        } else {
            if (StringUtils.isEmpty(context.getUserExtId())) {
                return new WalletQueryResult(ErrorConstants.PARAMS_VALUE_ERROR_CODE, "Invalid userExtId");
            }
            FinUser user = userService.queryByUserExtId(context.getUserExtId());
            if (null == user) {
                return new WalletQueryResult(ErrorConstants.PARAMS_VALUE_ERROR_CODE, "Not found userExtId");
            }

            PageHelper.startPage(context.getPageNum(), context.getPageSize());
//            walletList = walletService.queryByWalletNoAndAliasAndCurrencyForFuzzy(context.getFuzzySearch(), user.getFinId());
            walletList = walletService.query(BeanMap.create(context));
            pageInfoTmp = new PageInfo<>(walletList);
        }
        PageInfo<WalletAccountInfoVo> pageInfo = new PageInfo<>();
        BeanUtils.copyProperties(pageInfoTmp, pageInfo);
        pageInfo.setList(walletAccountInfoVoList);
        if (!CollectionUtils.isEmpty(walletList)) {
            Map<String, List<String>> finIdWithAccNoMap = new HashMap<>();

            int wSize = walletList.size();
            for (int i = 0; i < wSize; i++) {
                FinWallet wallet = walletList.get(i);
                WalletAccountInfoVo vo = WalletAccountInfoVo.getNew().copy(wallet);
//                vo.setBalance(BigDecimal.ZERO);
//                vo.setBalanceAvailable(BigDecimal.ZERO);
//                vo.setBalancePending(BigDecimal.ZERO);
//                vo.setBalanceFrozen(BigDecimal.ZERO);
                walletAccountInfoVoList.add(vo);

                List<String> accList = null;
                String finId = wallet.getFinId();
                if (finIdWithAccNoMap.containsKey(finId)) {
                    accList = finIdWithAccNoMap.get(finId);
                    accList.add(FinUtil.getAccNo(FinConstants.AccType.AVAILABLE.getVal(), wallet.getWalletNo()));
                    accList.add(FinUtil.getAccNo(FinConstants.AccType.PENDING.getVal(), wallet.getWalletNo()));
                    accList.add(FinUtil.getAccNo(FinConstants.AccType.FROZEN.getVal(), wallet.getWalletNo()));
                } else {
                    accList = new ArrayList<>();
                    accList.add(FinUtil.getAccNo(FinConstants.AccType.AVAILABLE.getVal(), wallet.getWalletNo()));
                    accList.add(FinUtil.getAccNo(FinConstants.AccType.PENDING.getVal(), wallet.getWalletNo()));
                    accList.add(FinUtil.getAccNo(FinConstants.AccType.FROZEN.getVal(), wallet.getWalletNo()));
                    finIdWithAccNoMap.put(finId, accList);
                }
            }

            FundingQueryBalanceParam fundingQueryBalanceParam = new FundingQueryBalanceParam();
            fundingQueryBalanceParam.setFinIdWithAccNoMap(finIdWithAccNoMap);
            FundingQueryBalanceResult fundingQueryBalanceResult = fundingAPIService.queryBalance(fundingQueryBalanceParam);

            List<FundingAccountInfo> fundingAccountInfoList = null;
            if (fundingQueryBalanceResult.isSuccess() && !CollectionUtils.isEmpty((fundingAccountInfoList = fundingQueryBalanceResult.getFundingAccountInfoList()))) {
                Map<String, List<FundingAccountInfo>> fundingAccountInfoMap = new HashMap<>();
                fundingAccountInfoList.stream().collect(Collectors.groupingBy(FundingAccountInfo::getAccGroupId, Collectors.toList()))
                        .forEach(fundingAccountInfoMap::put);

                for (int i = 0; i < wSize; i++) {
                    WalletAccountInfoVo vo = walletAccountInfoVoList.get(i);
                    List<FundingAccountInfo> fundingAccountInfoListSub = fundingAccountInfoMap.get(vo.getWalletNo());
                    if (!CollectionUtils.isEmpty(fundingAccountInfoListSub)) {
                        int size = fundingAccountInfoListSub.size();
                        for (int j = 0; j < size; j++) {
                            FundingAccountInfo fundingAccountInfo = fundingAccountInfoListSub.get(j);

                            String accNo = fundingAccountInfo.getAccNo();
                            String suffix = accNo.substring(accNo.length() - 3);
                            FinConstants.AccType accType = FinConstants.AccType.byVal(suffix);

                            if (null == accType) continue;
                            switch (accType) {
                                case AVAILABLE:
                                    vo.setBalanceAvailable(fundingAccountInfo.getBalance());
                                    break;
                                case PENDING:
                                    vo.setBalancePending(fundingAccountInfo.getBalance());
                                    break;
                                case FROZEN:
                                    vo.setBalanceFrozen(fundingAccountInfo.getBalance());
                                    break;
                            }
                        }
                    }
                }
            }
        }
        return new WalletQueryResult(pageInfo);
    }
}
