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

import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.account.common.ErrorConstants;
import com.liquidnet.service.account.common.FinConstants;
import com.liquidnet.service.account.exception.FinaccountException;
import com.liquidnet.service.account.funding.dto.base.FundingCallResult;
import com.liquidnet.service.account.funding.dto.base.FundingContextParam;
import com.liquidnet.service.account.funding.service.processor.FundingRegisterProcessor;
import com.liquidnet.service.account.util.FinUtil;
import com.liquidnet.service.account.wallet.dto.WalletRegisterResult;
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.FinDictService;
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 org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;
import java.util.Optional;

/**
 * WalletRegisterProcessService.class
 *
 * @author zhanggb
 * Created by IntelliJ IDEA at 2020/10/21
 */
@Service
public class WalletAccountRegisterProcessor extends WalletProcessorService {
    private static final Logger log = LoggerFactory.getLogger(WalletAccountRegisterProcessor.class);
    private Map<String, String> currencyDict = null;
    @Autowired
    private FundingRegisterProcessor fundingRegisterProcessor;
    @Autowired
    private FinDictService dictService;
    @Autowired
    private FinUserService userService;
    @Autowired
    private FinWalletService walletService;

    @Override
    public WalletRegisterResult checkInputParams(WalletContextParam context) {
        if (StringUtils.isEmpty(context.getUserExtId()) || context.getUserExtId().length() > 64) {
            return new WalletRegisterResult(ErrorConstants.PARAMS_VALUE_ERROR_CODE, "Invalid userExtId");
        }
        if (StringUtils.isEmpty(context.getUserExtName()) || context.getUserExtName().length() > 150) {
            return new WalletRegisterResult(ErrorConstants.PARAMS_VALUE_ERROR_CODE, "Invalid userExtName");
        }
        currencyDict = dictService.getDictValueForName(FinConstants.Dict.ACC_CURRENCY.name());
        if (StringUtils.isEmpty(context.getCurrency()) || !currencyDict.containsKey(context.getCurrency())) {
            return new WalletRegisterResult(ErrorConstants.PARAMS_VALUE_ERROR_CODE, "Invalid currency");
        }
        if (StringUtils.isNotEmpty(context.getAlias()) && context.getAlias().length() > 100) {
            return new WalletRegisterResult(ErrorConstants.PARAMS_VALUE_ERROR_CODE, "Toolong alias");
        }
        return new WalletRegisterResult();
    }

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

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public WalletRegisterResult doBussiness(WalletContextParam context) {
        // Verify that the subject is registered
        FinUser finUser = userService.queryByUserExtId(context.getUserExtId());

        // - - - - - register the user principal
        finUser = Optional.ofNullable(finUser).orElseGet(() -> this.createFinUser(context));

        String finId = finUser.getFinId();

        // - - - - - register the wallet
        FinWallet addWalletInfo = new FinWallet();
        addWalletInfo.setWalletNo(walletService.generateSeqForWalletNo(currencyDict.get(context.getCurrency())));
        addWalletInfo.setCurrency(context.getCurrency());
        addWalletInfo.setAlias(context.getAlias());
        addWalletInfo.setStatus(FinConstants.Status.NORMAL.getVal());
        addWalletInfo.setPayStatus(FinConstants.Status.NORMAL.getVal());
        addWalletInfo.setFinId(finId);
        addWalletInfo.setUserExtId(finUser.getUserExtId());
        addWalletInfo.setUserExtName(finUser.getUserExtName());
        addWalletInfo.setCreateTime(context.getCreateTime());
        addWalletInfo.setCreateOperator(context.getOperator());
        if (walletService.addWallet(addWalletInfo) <= 0) {
            log.warn("Add data failed:wallet:[tradeNo={},addInfo={}]", context.getTradeNo(), JsonUtils.toJson(addWalletInfo));
            return new WalletRegisterResult(ErrorConstants.WALLET_CREATE_ERROR_CODE, ErrorConstants.WALLET_CREATE_ERROR_DESC);
        }

        // - - - - - start of account opening
        FinConstants.AccType[] accTypes = FinConstants.AccType.values();
        for (int i = 0; i < accTypes.length; i++) {
            FinConstants.AccType accType = accTypes[i];

            FundingContextParam fundingRegisterParam = FundingContextParam.getNew();
            fundingRegisterParam.setCurrency(addWalletInfo.getCurrency());
            fundingRegisterParam.setAccAlias(addWalletInfo.getAlias());
            fundingRegisterParam.setFinId(addWalletInfo.getFinId());
            fundingRegisterParam.setAccType(accType.getVal());
            fundingRegisterParam.setAccGroupId(addWalletInfo.getWalletNo());

            FundingCallResult<?> fundingRegisterResult = fundingRegisterProcessor.service(fundingRegisterParam);

            if (null == fundingRegisterResult || !fundingRegisterResult.isSuccess()) {
                throw new FinaccountException(ErrorConstants.WALLET_CREATE_ERROR_CODE, "Wallet account creation failed");
            }
        }
        return new WalletRegisterResult(new String[]{addWalletInfo.getFinId(), addWalletInfo.getWalletNo()});
    }

    private FinUser createFinUser(WalletContextParam context) {
        FinUser finUser = new FinUser();
        finUser.setFinId(FinUtil.getFinId());
        finUser.setUserExtId(context.getUserExtId());
        finUser.setUserExtName(context.getUserExtName());
        finUser.setChannelId(context.getChannelId());
        finUser.setUserStatus(FinConstants.Status.NORMAL.getVal() + "");
        finUser.setUserFlag(FinConstants.AccFlag.BUSINESS.getVal());
        finUser.setCreateTime(context.getCreateTime());

        if (userService.addUser(finUser) <= 0) {
            log.warn("Add data failed:user:[{}]", JsonUtils.toJson(finUser));
            throw new FinaccountException(ErrorConstants.SUBJECT_CREATE_ERROR_CODE, ErrorConstants.SUBJECT_CREATE_ERROR_DESC);
        }
        return finUser;
    }
}
