package com.crm.ucard.service.impl;

import com.alibaba.fastjson.JSON;
import com.crm.rely.backend.core.constant.*;
import com.crm.rely.backend.core.entity.system.email.SysEmailSendEntity;
import com.crm.rely.backend.core.entity.ucard.crypto.currency.callback.*;
import com.crm.rely.backend.core.pojo.table.ucard.*;
import com.crm.rely.backend.exception.ServiceException;
import com.crm.rely.backend.service.EmailService;
import com.crm.rely.backend.util.*;
import com.crm.ucard.dao.repository.*;
import com.crm.ucard.service.CryptoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Slf4j
@Service
public class CryptoServiceImpl implements CryptoService {

    @Autowired
    private CardWalletAddressRepository cardWalletAddressRepository;
    @Autowired
    private UcardCryptoCallbackRecordRepository cryptoCallbackRecordRepository;
    @Autowired
    private UcardWalletRepository ucardWalletRepository;
    @Autowired
    private UcardWalletRecordRepository ucardWalletRecordRepository;
    @Autowired
    private CardBlockchainRateConfigRepository blockchainRateConfigRepository;
    @Autowired
    private EmailService emailService;
    @Autowired
    private CardMerchantUserRepository merchantUserRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void notify(CryptoAddressCallbackEntity entity) throws Exception {
        String idempotencyKey = entity.getIdempotencyKey();
        if (StringUtils.isEmpty(idempotencyKey)) {
            log.error("加密货币通知回调：idempotencyKey为空，{}", JSON.toJSONString(entity));
            return;
        }
        // 根据idempotencyKey 查询数据表是否存在该条数据，如果存在说明已经处理过
        UcardCryptoCallbackRecordTable callbackRecordTable = cryptoCallbackRecordRepository.findFirstByIdempotencyKey(idempotencyKey);
        if (callbackRecordTable != null) {
            log.error("加密货币通知回调：idempotencyKey已存在，数据重复，{}", JSON.toJSONString(entity));
            return;
        }
        CryptoDataEntity dataEntity = entity.getData();
        CryptoItemEntity itemEntity = dataEntity.getItem();
        String direction = itemEntity.getDirection();
        // 判读数据是转入还是转出
        if (StringUtils.isEmpty(direction) || !"incoming".equals(direction)) {
            log.error("加密货币通知回调：资金方向不是入账，暂不处理，{}", JSON.toJSONString(direction));
            return;
        }
        String event = dataEntity.getEvent();
        if (StringUtils.isEmpty(event)) {
            log.error("加密货币通知回调：event为空，暂不处理，{}", JSON.toJSONString(entity));
            return;
        }
        String address = itemEntity.getAddress();
        String blockchain = itemEntity.getBlockchain();
        // 根据地址和区块链查询用户
        CardWalletAddressTable table = cardWalletAddressRepository.getFirstByAddressAndBlockchain(address, blockchain);
        if (table == null || StringUtils.isEmpty(table.getUniqueId())) {
            log.error("加密货币通知回调：该地址未绑定用户，{}", JSON.toJSONString(entity));
            return;
        }
        UcardWalletTable walletTable = ucardWalletRepository.getFirstByUniqueId(table.getUniqueId());
        if (walletTable == null) {
            log.error("加密货币通知回调：用户钱包不存在，{}", JSON.toJSONString(entity));
            return;
        }
        String amount = null;
        String unit = null;
        if ("KASPA_ADDRESS_COINS_TRANSACTION_CONFIRMED".equals(event) || "ADDRESS_COINS_TRANSACTION_CONFIRMED".equals(event)) {
            amount = itemEntity.getAmount();
            unit = itemEntity.getUnit();
        } else if ("ADDRESS_TOKENS_TRANSACTION_CONFIRMED".equals(event)) {
            CryptoTokenEntity tokenEntity = itemEntity.getToken();
            amount = tokenEntity.getAmount();
            unit = tokenEntity.getSymbol();
        }
        BigDecimal addAmount = StringUtils.isEmpty(amount) ? BigDecimal.ZERO : new BigDecimal(amount);
        // 金额为空或负暂不处理
        if (addAmount.compareTo(BigDecimal.ZERO) <= 0) {
            log.error("加密货币通知回调,通知金额为空，暂不处理，{}", JSON.toJSONString(entity));
            return;
        }
        // 查询币种汇率
        CardBlockchainRateConfigTable rateConfigTable = blockchainRateConfigRepository.getByCurrencyAndConvertCurrencyAndEnableStatus("USDT", unit, 1);
        if (rateConfigTable == null || rateConfigTable.getExchangeRate() == null) {
            log.error("加密货币通知回调,币种汇率不存在，{}", JSON.toJSONString(entity));
            throw new ServiceException("加密货币通知回调,币种汇率不存在");
        }
        addAmount = addAmount.multiply(rateConfigTable.getExchangeRate()).setScale(2, RoundingMode.HALF_UP);
        BigDecimal balance = walletTable.getBalance().add(addAmount);
        walletTable.setBalance(balance);
        ucardWalletRepository.save(walletTable);

        UcardWalletRecordTable recordTable = new UcardWalletRecordTable();
        recordTable.setWalletId(walletTable.getId());
        recordTable.setCId(walletTable.getCId());
        recordTable.setUniqueId(walletTable.getUniqueId());
        recordTable.setSerial(GetRandom.getOrderNo(PayConstant.UCARD_HEAD));
        recordTable.setAmount(addAmount);
        recordTable.setFee(BigDecimal.ZERO);
        recordTable.setType(9);
        recordTable.setStatus(2);
        recordTable.setAddTime(new Date());
        ucardWalletRecordRepository.save(recordTable);
        // 保存记录信息
        CryptoMinedInBlockEntity blockEntity = itemEntity.getMinedInBlock();
        callbackRecordTable = new UcardCryptoCallbackRecordTable();
        callbackRecordTable.setUniqueId(walletTable.getUniqueId());
        BeanUtils.copyProperties(entity, callbackRecordTable);
        BeanUtils.copyProperties(dataEntity, callbackRecordTable);
        BeanUtils.copyProperties(itemEntity, callbackRecordTable);
        BeanUtils.copyProperties(blockEntity, callbackRecordTable);
        if (itemEntity.getToken() != null) {
            BeanUtils.copyProperties(itemEntity.getToken(), callbackRecordTable);
        }
        callbackRecordTable.setUnit(unit);
        callbackRecordTable.setReceivedAmount(addAmount);
        cryptoCallbackRecordRepository.save(callbackRecordTable);
        // 发邮件给客户通知到账邮件
        sendEncryptedWalletSuccessEmail(callbackRecordTable);
    }

    /**
     * 回调成功给客户发送邮件
     */
    private void sendEncryptedWalletSuccessEmail(UcardCryptoCallbackRecordTable table) throws ServiceException {
        CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(table.getUniqueId());

        //构建map 用于后面邮件模版替换
        String name = CustomInfoUtil.getName(userTable.getFirstName(), null, userTable.getLastName());
        Map<String, String> map = new HashMap<>(8);

        map.put(MapConstants.DATE_TIME, DateUtil.formatTime(new Date()));
        map.put(MapConstants.NAME, name);
        map.put(MapConstants.WALLET_ADDRESS, table.getAddress());
        map.put(MapConstants.AMOUNT, table.getAmount());
        map.put(MapConstants.CURRENCY_TYPE, table.getUnit());
        map.put(MapConstants.DEPOSIT_TRANSFORM_CURRENCY, "USD");
        map.put(MapConstants.TRANSFORM_AMOUNT, String.valueOf(table.getReceivedAmount()));
        map.put(MapConstants.SUCCESS_TIME, DateUtil.formatTimestamp(Long.valueOf(table.getTimestamp())));

        SysEmailSendEntity sysEmailSendEntity = new SysEmailSendEntity();
        sysEmailSendEntity.setSubject("ENCRYPTED WALLET TRANSACTION SUCCESS");
        sysEmailSendEntity.setEmailSendEnum(EmailSendEnum.ENCRYPTED_WALLET_TRANSACTION_SUCCESS);
        sysEmailSendEntity.setMap(map);
        if (CountryUtil.isCN(userTable.getCountry())) {
            sysEmailSendEntity.setTemplateName(SystemEmailCodeConstants.ENCRYPTED_WALLET_TRANSACTION_SUCCESS_CN);
        } else {
            sysEmailSendEntity.setTemplateName(SystemEmailCodeConstants.ENCRYPTED_WALLET_TRANSACTION_SUCCESS_EN);
        }
        sysEmailSendEntity.setUsers(userTable.getEmail());
        try {
            emailService.sendEmail(sysEmailSendEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
