package com.liquidnet.service.bank.currencycloud.service.impl;
import com.alibaba.fastjson.JSON;
import com.currencycloud.client.CurrencyCloudClient;
import com.currencycloud.client.exception.ApiException;
import com.currencycloud.client.model.Pagination;
import com.currencycloud.client.model.Pagination.SortOrder;
import com.currencycloud.client.model.Transaction;
import com.currencycloud.client.model.Transactions;
import com.liquidnet.common.exception.constant.ErrorCode;
import com.liquidnet.service.ResponseDto;
import com.liquidnet.service.bank.common.BankErrorCode;
import com.liquidnet.service.bank.common.BankResultDto;
import com.liquidnet.service.bank.currencycloud.dto.BankCcTransactionQuery;
import com.liquidnet.service.bank.currencycloud.entity.BankCcTransaction;
import com.liquidnet.service.bank.currencycloud.mapper.BankCcTransactionMapper;
import com.liquidnet.service.bank.currencycloud.service.IBankCcTransactionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicReference;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lightnet
 * @since 2020-09-08
 */
@Service("bankCcTransactionService")
@Slf4j
public class BankCcTransactionServiceImpl implements IBankCcTransactionService {

    @Autowired
    CurrencyCloudClient currencyCloudClient;

    @Autowired
    BankCcTransactionMapper bankCcTransactionMapper;

    @Override
    public int insertOrUpdate(BankCcTransaction bankCcTransaction) {
        BankCcTransaction bankCcTransaction1 = bankCcTransactionMapper.selectById(bankCcTransaction.getId());
        if (bankCcTransaction1 == null) {
            bankCcTransaction.setCreateTime(LocalDateTime.now());
            return bankCcTransactionMapper.insert(bankCcTransaction);
        } else {
            bankCcTransaction.setUpdateTime(LocalDateTime.now());
            return bankCcTransactionMapper.updateById(bankCcTransaction);
        }
    }

    @Override
    public ResponseDto<Transactions> findTransactions(BankCcTransactionQuery query) {
        String logFx = "cc find transactions.";
        AtomicReference<Transactions> transactions = new AtomicReference<>();
        try {
            String contactId = query.getContactId();
            log.info(logFx + "request contactId=[{}],BankCcTransactionQuery=[{}]", query.getContactId(), JSON.toJSONString(query));
            this.transfer(query);
            BigDecimal amount = StringUtils.isEmpty(query.getAmount()) ? null : new BigDecimal(query.getAmount());
            Transaction example = Transaction.createExample(query.getCurrency(), amount, query.getAction(), query.getRelatedEntityType(), query.getRelatedEntityId(), query.getRelatedEntityShortReference(), query.getStatus(), query.getType(), query.getReason());
            example.setScope(StringUtils.isEmpty(query.getScope()) ? "clients" : query.getScope());

            Pagination paginationReq = new Pagination();
            paginationReq.setPage(StringUtils.isEmpty(query.getPagenNum()) ? 1 : Integer.parseInt(query.getPagenNum()));
            paginationReq.setPerPage(25);
            paginationReq.setOrderAscDesc(SortOrder.desc);
            if (!StringUtils.isEmpty(contactId)) {
                Runnable runnable = () -> transactions.set(currencyCloudClient.findTransactions(example, paginationReq));
                currencyCloudClient.onBehalfOfDo(contactId, runnable);
            } else {
                transactions.set(currencyCloudClient.findTransactions(example, paginationReq));
            }
            log.info(logFx + "response transactions=[{}]", transactions.toString());
            // todo-lichen 未完成,暂时不考虑做持久化操作
            return ResponseDto.success(transactions.get());

        } catch (ApiException e) {
            log.error(logFx + "api eroor, errorCode=[{}],errors=[{}]", e.getErrorCode(), e.getErrors());
            return ResponseDto.failure(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            log.error(logFx + "exception eroor:[{}]", JSON.toJSONString(e));
            return ResponseDto.failure(ErrorCode.HTTP_SYSTEM_ERROR);
        }
    }

    @Override
    public BankResultDto<BankCcTransaction> retrieveTransaction(String transactionId, String contactId) {
        String logFx = "cc get transactions,transactionId=[" + transactionId + "],contactId=[" + contactId + "]";
        BankCcTransaction bankCcTransaction = new BankCcTransaction();
        try {
            Runnable runnable = () -> {
                Transaction transaction = currencyCloudClient.retrieveTransaction(transactionId);

                log.info(logFx + "response,transaction=[{}]", transaction.toString());

                BeanUtils.copyProperties(transaction, bankCcTransaction);
                BankCcTransaction selectTrans = bankCcTransactionMapper.selectById(transaction.getId());
                if (selectTrans == null) {
                    // 持久化数据库
                    bankCcTransaction.setCreateTime(LocalDateTime.now());
                    bankCcTransactionMapper.insert(bankCcTransaction);
                } else {
                    bankCcTransaction.setUpdateTime(LocalDateTime.now());
                    bankCcTransactionMapper.updateById(bankCcTransaction);
                }
            };
            currencyCloudClient.onBehalfOfDo(contactId, runnable);
            return BankResultDto.success(bankCcTransaction);
        } catch (ApiException e) {
            log.error(logFx + "api eroor, errorCode=[{}],errors=[{}]", e.getErrorCode(), e.getErrors());
            return BankResultDto.failure(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            log.error(logFx + "exception eroor:[{}]", JSON.toJSONString(e));
            return BankResultDto.failure(BankErrorCode.BANK_CC_001001);
        }
    }

    void transfer(Object erpReqDTO) {
        Field[] declaredFields = erpReqDTO.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            try {
                String o = field.get(erpReqDTO) + "";
                if (o.equals("")) {
                    field.set(erpReqDTO, null);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

}
