package com.liquidnet.service.adam.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.liquidnet.service.account.common.FinConstants;
import com.liquidnet.service.account.wallet.dto.WalletTransactionParam;
import com.liquidnet.service.account.wallet.vo.WalletTransactionInfoVo;
import com.liquidnet.service.adam.constant.AdamSysSequenceConstants;
import com.liquidnet.service.adam.constant.AdamTransactionConstants;
import com.liquidnet.service.adam.dto.base.AdamResultDto;
import com.liquidnet.service.adam.entity.AdamConversion;
import com.liquidnet.service.adam.entity.AdamFunding;
import com.liquidnet.service.adam.entity.AdamPayout;
import com.liquidnet.service.adam.entity.AdamTransaction;
import com.liquidnet.service.adam.incrementer.CustomIdGenerator;
import com.liquidnet.service.adam.mapper.AdamTransactionMapper;
import com.liquidnet.service.adam.mapper.SysSequenceMapper;
import com.liquidnet.service.adam.service.*;
import com.liquidnet.service.adam.service.feign.fin.IAdamFeignAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 交易记录表 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2020-10-30
 */
@Service
public class AdamTransactionApiServiceImpl implements IAdamTransactionApiService {

    @Autowired
    private SysSequenceMapper sysSequenceMapper;

    @Autowired
    CustomIdGenerator customIdGenerator;

    @Autowired
    private IAdamFeignAccountService adamFeignAccountService;

    @Autowired
    private IAdamTransactionService adamTransactionService;

    @Autowired
    private IAdamConversionService adamConversionService;

    @Autowired
    private IAdamFundingService adamFundingService;

    @Autowired
    private IAdamPayoutService adamPayoutService;

    @Autowired
    private AdamTransactionMapper adamTransactionMapper;

    @Override
    public String generateNumber(String type) {
        StringBuilder idString = new StringBuilder();
        LocalDate now = LocalDate.now();
        String dayOfMonth = String.valueOf(now.getDayOfMonth());
        if (dayOfMonth.length() == 1) {
            dayOfMonth = "0" + dayOfMonth;
        }
        idString.append(now.getYear() % 100).append(now.getMonthValue()).append(dayOfMonth);
        idString.append(type).append("-");
        Long seq = sysSequenceMapper.generateSeqNo(AdamSysSequenceConstants.SEQ_TRANSACTION_NUMBER);
        DecimalFormat countFormat = new DecimalFormat("000000");
        String format = countFormat.format(seq);
        idString.append(format);
        return idString.toString();
    }


    @Override
    public AdamResultDto<String> pushFinTransaction(AdamTransaction param) {
        WalletTransactionParam walletTransactionParam = new WalletTransactionParam();
        walletTransactionParam.setWalletNo(param.getFinWalletNo());
        walletTransactionParam.setTransType(getTransType(param.getType(), param.getStatus(), param.getFundDirection()));
        walletTransactionParam.setAmount(param.getFundAmount());
        walletTransactionParam.setTracingType(param.getType());
        walletTransactionParam.setTracingNo(param.getId());
        walletTransactionParam.setTracingTime(LocalDateTime.now());
        walletTransactionParam.setTracingTitle(param.getType());
        return adamFeignAccountService.transaction(walletTransactionParam);

    }

    @Override
    public int updateFunding(AdamTransaction transaction, AdamFunding funding) {
        LocalDateTime now = LocalDateTime.now();
        if (transaction != null) {
            transaction.setUpdateTime(now);
            adamTransactionService.updateById(transaction);
        }
        if (funding != null) {
            funding.setUpdateTime(now);
            adamFundingService.updateById(funding);
        }
        return 0;
    }

    @Override
    public int updatePayout(AdamTransaction transaction, AdamPayout payout) {
        LocalDateTime now = LocalDateTime.now();
        if (transaction != null) {
            transaction.setUpdateTime(now);
            adamTransactionService.updateById(transaction);
        }
        if (payout != null) {
            payout.setUpdateTime(now);
            adamPayoutService.updateById(payout);
        }
        return 0;
    }

    @Override
    @Transactional
    public int updateConversion(AdamTransaction transaction, AdamConversion conversion) {
        LocalDateTime now = LocalDateTime.now();
        if (transaction != null) {
            transaction.setUpdateTime(now);
            adamTransactionService.updateById(transaction);
        }
        if (conversion != null) {
            conversion.setUpdateTime(now);
            adamConversionService.updateById(conversion);
        }
        return 0;
    }

    @Override
    @Async
    public void asyncUpdateBalance(List<WalletTransactionInfoVo> list) {
        AdamTransaction transaction = null;

        for (WalletTransactionInfoVo vo : list) {
            transaction = new AdamTransaction();
            transaction.setFinWalletAvailableBalance(vo.getBalanceAvailable());
            transaction.setFinWalletTotalBalance(vo.getBalanceAvailable().add(vo.getBalancePending()).add(vo.getBalanceFrozen()));
            LambdaUpdateWrapper<AdamTransaction> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(AdamTransaction::getFinWalletTransactionId, vo.getTracingNo());
            adamTransactionMapper.update(transaction, updateWrapper);
        }

    }

    private FinConstants.TransType getTransType(String type, String status, String fundDirection) {
        AdamTransactionConstants.TypeEnum enumByCode = AdamTransactionConstants.TypeEnum.getEnumByCode(type);
        if (enumByCode == null) {
            return null;
        }
        switch (enumByCode) {
            case FUNDING:
                if (AdamTransactionConstants.FundsDirectionEnum.CREDIT.getCode().equals(fundDirection)) {
                    if (AdamTransactionConstants.StatusEnum.PROCESSING.getCode().equals(status)) {
                        return FinConstants.TransType.CREDIT_ONWAY;
                    } else if (AdamTransactionConstants.StatusEnum.COMPLETED.getCode().equals(status)) {
                        return FinConstants.TransType.CREDIT_CONFIRM;
                    } else if (AdamTransactionConstants.StatusEnum.FAILED.getCode().equals(status)) {
                        return FinConstants.TransType.CREDIT_CANCEL;
                    }
                }
                break;
            case PAYOUT:
                if (AdamTransactionConstants.FundsDirectionEnum.DEBIT.getCode().equals(fundDirection)) {
                    if (AdamTransactionConstants.StatusEnum.READY_TO_PROCESS.getCode().equals(status)) {
                        return FinConstants.TransType.DEBIT_ONWAY;
                    } else if (AdamTransactionConstants.StatusEnum.AWAITING_FUNDS.getCode().equals(status)) {
                        return FinConstants.TransType.DEBIT_ONWAY;
                    } else if (AdamTransactionConstants.StatusEnum.COMPLETED.getCode().equals(status)) {
                        return FinConstants.TransType.DEBIT_CONFIRM;
                    } else if (AdamTransactionConstants.StatusEnum.FAILED.getCode().equals(status)) {
                        return FinConstants.TransType.DEBIT_CANCEL;
                    }
                }
                break;
            case FX_CONVERSION:
                if (AdamTransactionConstants.FundsDirectionEnum.DEBIT.getCode().equals(fundDirection)) {

                    if (AdamTransactionConstants.StatusEnum.READY_TO_SETTLE.getCode().equals(status)) {
                        return FinConstants.TransType.DEBIT_ONWAY;
                    } else if (AdamTransactionConstants.StatusEnum.COMPLETED.getCode().equals(status)) {
                        return FinConstants.TransType.DEBIT_CONFIRM;
                    } else if (AdamTransactionConstants.StatusEnum.FAILED.getCode().equals(status)) {
                        return FinConstants.TransType.DEBIT_CANCEL;
                    }
                } else if (AdamTransactionConstants.FundsDirectionEnum.CREDIT.getCode().equals(fundDirection)) {
                    if (AdamTransactionConstants.StatusEnum.READY_TO_SETTLE.getCode().equals(status)) {
                        return FinConstants.TransType.CREDIT_ONWAY;
                    } else if (AdamTransactionConstants.StatusEnum.COMPLETED.getCode().equals(status)) {
                        return FinConstants.TransType.CREDIT_CONFIRM;
                    } else if (AdamTransactionConstants.StatusEnum.FAILED.getCode().equals(status)) {
                        return FinConstants.TransType.CREDIT_CANCEL;
                    }
                }
                break;
        }

        return null;
    }

}
