package com.crm.pay.service.impl.pay;

import com.alibaba.fastjson.JSON;
import com.crm.pay.dao.repository.FinanceDepositRepository;
import com.crm.pay.dao.repository.FinanceWithdrawRepository;
import com.crm.pay.dto.finance.withdraw.automatic.FinanceWithdrawUcardpayDto;
import com.crm.pay.entity.FinanceDepositUcardEntity;
import com.crm.pay.entity.callback.UcardPayCallbackEntity;
import com.crm.pay.entity.property.UcardPayPropertyEntity;
import com.crm.pay.entity.property.UcardPayWithdrawPropertyEntity;
import com.crm.pay.entity.ucard.CardSendEmailCodeEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.FinanceWithdrawService;
import com.crm.pay.service.UcardPayService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.core.constant.EmailSendEnum;
import com.crm.rely.backend.core.constant.MapConstants;
import com.crm.rely.backend.core.dto.base.BaseResultDto;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.dto.finance.withdraw.FinanceWithdrawDto;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.pay.entity.finance.withdraw.FinanceWithdrawApproveChannelEntity;
import com.crm.pay.entity.finance.withdraw.FinanceWithdrawApproveChannelSubmitEntity;
import com.crm.pay.entity.finance.withdraw.automatic.FinanceWithdrawInfoEntity;
import com.crm.pay.entity.finance.withdraw.automatic.FinanceWithdrawUcardpayEntity;
import com.crm.rely.backend.core.entity.system.email.SysEmailSendEntity;
import com.crm.rely.backend.core.exception.PayValidatedException;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.model.pojo.table.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.FinanceWithdrawTable;
import com.crm.rely.backend.model.pojo.table.SysRemitChannelTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.service.EmailService;
import com.crm.rely.backend.util.*;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Connection;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
@Service
public class UcardPayServiceImpl extends BasePayServiceImpl implements UcardPayService {

    @Autowired
    private FinanceDepositService financeDepositService;
    /*@Autowired
    private FinanceAgentWithdrawRepository financeAgentWithdrawRepository;*/
    @Autowired
    private FinanceWithdrawRepository financeWithdrawRepository;
    @Autowired
    private FinanceWithdrawService financeWithdrawService;
    /*@Autowired
    private UcardCardRepository cardRepository;
    @Autowired
    private CardMerchantUserRepository merchantUserRepository;*/
    @Autowired
    private EmailService emailService;
    @Autowired
    private FinanceDepositRepository financeDepositRepository;

    public static void main(String[] args) {
        String con = "{\n" +
                "  \"baseUrl\":\"http://192.168.0.25:8700\",\n" +
                "  \"depositUrl\":\"/ucard/wallet/deposit\",\n" +
                "  \"callbackUrl\":\"http://192.168.0.25:8004/ucard/callback\",\n" +
                "}";
        System.out.println(AESUtil.encrypt(con, "bfa5559109f94c78af615bcf00d52060"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String save(FinanceDepositAddEntity balanceSaveEntity) throws Exception {
        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.UCARD_PAY_KEY);

        balanceSaveEntity.setCurrency(channel.getCurrency());
        balanceSaveEntity.setTransformCurrency(channel.getTransformCurrency());

        FinanceDepositTable balanceTable = financeDepositService.save(balanceSaveEntity, channel);

        
        return balanceTable.getSerial();
    }

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto callback(UcardPayCallbackEntity callbackEntity) throws Exception {
        log.info(String.format("callback data:%s", JSON.toJSONString(callbackEntity)));
        if (Strings.isNullOrEmpty(callbackEntity.getSign())) {
            return BaseResultDto.error("signature is empty");
        }

        String sign = getSign(callbackEntity);
        if (!callbackEntity.getSign().equals(sign)) {
            return BaseResultDto.error("signature error");
        }

        int status = PayConstants.CALLBACE_PROCESSING_STATUS;
        if (2 == callbackEntity.getStatus()) {
            status = PayConstants.CALLBACE_SUCCESS_STATUS;
        } else if (3 == callbackEntity.getStatus()) {
            status = PayConstants.CALLBACE_FAIL_STATUS;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(callbackEntity.getOrderNo(), callbackEntity.getInternalOrderNo(),
                        status, callbackEntity);
        balanceCallbackUpdateEntity.setTransformAmount(callbackEntity.getAmount());

        if (StringUtils.isNotEmpty(callbackEntity.getApproveDesc())) {
            balanceCallbackUpdateEntity.setApproveDesc(callbackEntity.getApproveDesc());
        }
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
        return BaseResultDto.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void validated(FinanceDepositUcardEntity entity) throws ServiceException {
        /*if ("1".equals(entity.getType())) {
            UcardCardTable cardTable = cardRepository.findFirstByCardNumber(entity.getCardNumber());
            if (!entity.getCvv().equals(cardTable.getCvv())) {
                throw new ServiceException(Constants.CVV_ERROR);
            }
            if (!entity.getPin().equals(cardTable.getPin())) {
                throw new ServiceException(Constants.PASSWORD_ERROR);
            }
        }
        existByEmail(entity.getEmail());
        emailService.validateCode(entity.getEmail(), entity.getEmailCode());*/
    }

    /**
     * 验证邮箱是否已存在
     *
     * @param email
     * @throws ServiceException
     */
    /*private void existByEmail(String email) throws ServiceException {
        boolean existByEmail = merchantUserRepository.existsByEmail(email);
        if (!existByEmail) {
            throw new ServiceException(Constants.EMAIL_IS_EXIST_ERROR);
        }
    }*/


    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto pay(FinanceDepositUcardEntity entity) throws Exception {
        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.UCARD_PAY_KEY);
        //通道配置实体
        UcardPayPropertyEntity propertyEntity = getPayProperty(channel, UcardPayPropertyEntity.class);
        FinanceDepositTable balanceTable = financeDepositService.getBySerial(entity.getSerial());
        // 判断订单是否处理过，是否过期
        Date payTime = DateUtil.operationMinute(balanceTable.getAddTime(), PayConstants.UCARD_PAY_TYPE_REMIT_PAY_TIME);
        if (!balanceTable.getCallbackStatus().equals(PayConstants.CALLBACE_PROCESSING_STATUS)
                || balanceTable.getSubmitStatus().equals(PayConstants.SUBMIT_PROCESSING_STATUS)
                || !PayConstants.APPLY_STATUS.equals(balanceTable.getStatus())
                || payTime.getTime() < System.currentTimeMillis()) {
            return BaseResultDto.error(PayConstants.ORDER_EXPIRED);
        }
        String orderNo = balanceTable.getSerial() + "_" + balanceTable.getLogin();
        BigDecimal fee = BigDecimal.ZERO;
        if (balanceTable.getAmount() != null && balanceTable.getAmount().compareTo(BigDecimal.ZERO) > 0
                && balanceTable.getDepositAmount() != null && balanceTable.getDepositAmount().compareTo(BigDecimal.ZERO) > 0) {
            fee = balanceTable.getAmount().subtract(balanceTable.getDepositAmount());
        }

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("cId", balanceTable.getCId());
        map.put("orderNo", orderNo);
        map.put("amount", String.format("%.2f", balanceTable.getTransformAmount().doubleValue()));
        map.put("callBackUrl", propertyEntity.getCallbackUrl());
        map.put("fee", String.format("%.2f", fee.doubleValue()));
        map.put("withdrawInfoType", 0);
        map.put("type", entity.getType());
        map.put("cardNumber", entity.getCardNumber());

        String signString = MapUtil.getStringSortByKey(MapUtil.convertToStringMap(map));
        String sign = MD5Util.getMD5(signString);
        map.put("sign", sign);
        // 标记处理过
        balanceTable.setSubmitStatus(PayConstants.SUBMIT_PROCESSING_STATUS);
        financeDepositRepository.save(balanceTable);

        Connection.Response response = HttpUtil.post(propertyEntity.getBaseUrl() + propertyEntity.getDepositUrl(),
                JSON.toJSONString(map));
        log.info(String.format("url:%s,json:%s,body:%s", propertyEntity.getBaseUrl() + propertyEntity.getDepositUrl()
                , JSON.toJSON(map), response.body()));

        BaseResultDto requestEntity = JSON.parseObject(response.body(), BaseResultDto.class);
        if (requestEntity == null || requestEntity.getCode() != 200) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        return BaseResultDto.success();
    }

    @Override
    public FinanceWithdrawUcardpayDto withdrawInfo(FinanceWithdrawInfoEntity entity) throws Exception {
        FinanceWithdrawDto withdrawDto = null;
        if (entity.getWithdrawInfoType() == null || entity.getWithdrawInfoType().equals(1)) {
            withdrawDto = financeWithdrawService.searchSingle(entity.getId());

        } else {
            //withdrawDto = financeAgentWithdrawService.searchSingle(entity.getId());
        }
        entity.setPayType(PayConstants.UCARD_PAY_TYPE_REMIT);

        SysRemitChannelTable withdrawChannel = getWithdrawChannel(entity.getPayType());

        FinanceWithdrawUcardpayDto dto = new FinanceWithdrawUcardpayDto();
        dto.setAmount(withdrawDto.getTransformAmount() == null ? null :
                withdrawDto.getTransformAmount().setScale(2, BigDecimal.ROUND_DOWN));
        dto.setRealName(withdrawDto.getName());

        dto.setId(withdrawDto.getId());
        dto.setWithdrawUrl(withdrawChannel.getWithdrawUrl());
        dto.setSerial(withdrawDto.getSerial());
        dto.setPayType(entity.getPayType());
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String withdraw(FinanceWithdrawUcardpayEntity entity) throws Exception {
        FinanceWithdrawDto withdrawDto = null;
        if (entity.getWithdrawInfoType() == null || entity.getWithdrawInfoType().equals(1)) {
            withdrawDto = financeWithdrawService.searchSingle(entity.getId());

        } else {
            //withdrawDto = financeAgentWithdrawService.searchSingle(entity.getId());
        }
        entity.setCId(withdrawDto.getCId());
        entity.setSerial(withdrawDto.getSerial());
        entity.setLogin(withdrawDto.getLogin());

        BigDecimal feeAmount = withdrawDto.getAmount().subtract(withdrawDto.getTransformAmount());

        UcardPayWithdrawPropertyEntity withdrawProperty = getWithdrawProperty(PayConstants.UCARD_PAY_TYPE_REMIT,
                UcardPayWithdrawPropertyEntity.class);

        String status = payout(entity, withdrawProperty, feeAmount);
        if (StringUtils.isEmpty(status) || !PayConstants.WALLET_IS_EMPTY.equals(status)) {
            FinanceWithdrawApproveChannelSubmitEntity financeWithdrawApproveChannelSubmitEntity =
                    new FinanceWithdrawApproveChannelSubmitEntity();
            financeWithdrawApproveChannelSubmitEntity.setSubmitStatus(PayConstants.PASSED_STATUS);
            financeWithdrawApproveChannelSubmitEntity.setId(entity.getId());
            financeWithdrawApproveChannelSubmitEntity.setActualPayType(entity.getPayType());
            if (entity.getWithdrawInfoType() == null || entity.getWithdrawInfoType().equals(1)) {
                financeWithdrawService.approve(financeWithdrawApproveChannelSubmitEntity);

            } else {
                //financeAgentWithdrawService.approve(financeWithdrawApproveChannelSubmitEntity);
            }
        }
        return null;
    }

    private String payout(FinanceWithdrawUcardpayEntity entity, UcardPayWithdrawPropertyEntity propertyEntity,
                          BigDecimal feeAmount) throws ServiceException, IOException, PayValidatedException {
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("cId", entity.getCId());
        map.put("orderNo", entity.getSerial());
        map.put("amount", String.format("%.2f", entity.getAmount().doubleValue()));
        map.put("fee", String.format("%.2f", feeAmount.doubleValue()));
        map.put("withdrawInfoType", entity.getWithdrawInfoType());
        map.put("type", "");
        map.put("cardNumber", "");
        if (entity.getWithdrawInfoType() == null || entity.getWithdrawInfoType().equals(1)) {
            map.put("callBackUrl", propertyEntity.getCallbackUrl());
        } else {
            map.put("callBackUrl", propertyEntity.getAgentCallbackUrl());
        }

        String signString = MapUtil.getStringSortByKey(MapUtil.convertToStringMap(map));
        String sign = MD5Util.getMD5(signString);
        map.put("sign", sign);

        Connection.Response response = HttpUtil.post(propertyEntity.getBaseUrl() + propertyEntity.getWithdrawUrl(),
                JSON.toJSONString(map));
        log.info(String.format("url:%s,json:%s,body:%s",
                propertyEntity.getBaseUrl() + propertyEntity.getWithdrawUrl(), JSON.toJSON(map), response.body()));

        BaseResultDto requestEntity = JSON.parseObject(response.body(), BaseResultDto.class);
        if (requestEntity == null || requestEntity.getCode() != 200) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }
        if (PayConstants.WALLET_IS_EMPTY.equals(requestEntity.getData())) {
            return PayConstants.WALLET_IS_EMPTY;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto withdrawCallback(Integer withdrawType, UcardPayCallbackEntity callbackEntity) throws Exception {
        log.info(String.format("callback data:%s", JSON.toJSONString(callbackEntity)));
        if (Strings.isNullOrEmpty(callbackEntity.getSign())) {
            return BaseResultDto.error("signature is empty");
        }

        String sign = getSign(callbackEntity);
        if (!callbackEntity.getSign().equals(sign)) {
            return BaseResultDto.error("signature error");
        }

        FinanceWithdrawApproveChannelEntity financeWithdrawApproveChannelEntity =
                new FinanceWithdrawApproveChannelEntity();
        financeWithdrawApproveChannelEntity.setChannelSerial(callbackEntity.getInternalOrderNo());
        if (StringUtils.isNotEmpty(callbackEntity.getApproveDesc())) {
            financeWithdrawApproveChannelEntity.setApproveDesc(callbackEntity.getApproveDesc());
        }

        if (2 == callbackEntity.getStatus()) {
            financeWithdrawApproveChannelEntity.setCallbackStatus(PayConstants.CALLBACE_SUCCESS_STATUS);
        } else {
            financeWithdrawApproveChannelEntity.setCallbackStatus(PayConstants.CALLBACE_FAIL_STATUS);
        }
        financeWithdrawApproveChannelEntity.setSerial(callbackEntity.getOrderNo());

        /**
         * 更新数据
         */

        if (withdrawType == null || withdrawType.equals(1)) {
            financeWithdrawService.approve(financeWithdrawApproveChannelEntity);

        } else {
            //financeAgentWithdrawService.channel(financeWithdrawApproveChannelEntity);
        }

        return BaseResultDto.success();
    }

    /**
     * agent快速到账
     */
   /* @JmsListener(destination = Constants.UCARD_CARD_AGENT_FAST_WITHDRAW)
    @Transactional(rollbackFor = Exception.class)
    public void ucardAgentFastWithdrawCallback(String content) throws Exception {
        log.info(String.format("UCARD_CARD_AGENT_FAST_WITHDRAW,content:%s", content));
        FinanceAgentWithdrawTable table = JSON.parseObject(content, FinanceAgentWithdrawTable.class);
        if (table == null) {
            log.error("UCARD_CARD_AGENT_FAST_WITHDRAW,callbackEntity is null");
            return;
        }

        table.setStatus(PayConstants.PASSED_STATUS);
        table.setWithdrawStatus(Constants.MANAGER_COMPLETED_STATUS);
        table.setOperationType(Constants.OPERATION_TYPE_AUTOMATIC);
        table.setActualPayType(table.getPayType());
        financeAgentWithdrawRepository.save(table);
        FinanceWithdrawUcardpayEntity entity = new FinanceWithdrawUcardpayEntity();
        BeanUtils.copyProperties(table, entity);
        entity.setWithdrawInfoType(2);
        entity.setAmount(table.getTransformAmount());

        withdraw(entity);
    }*/

    /**
     * 快速到账
     */

    @JmsListener(destination = PayConstants.UCARD_CARD_FAST_WITHDRAW)
    @Transactional(rollbackFor = Exception.class)
    public void ucardFastWithdrawCallback(String content) throws Exception {
        log.info(String.format("UCARD_CARD_FAST_WITHDRAW,content:%s", content));
        FinanceWithdrawTable table = JSON.parseObject(content, FinanceWithdrawTable.class);
        if (table == null) {
            log.error("UCARD_CARD_FAST_WITHDRAW,callbackEntity is null");
            return;
        }

        FinanceWithdrawUcardpayEntity entity = new FinanceWithdrawUcardpayEntity();
        BeanUtils.copyProperties(table, entity);
        entity.setWithdrawInfoType(1);
        entity.setAmount(table.getTransformAmount());

        if (financeWithdrawService.exFastWithdraw(entity.getId())) {

            withdraw(entity);
        }
    }

    /**
     * 回调请求加密sign
     *
     * @param callDataEntity
     * @return
     * @throws ServiceException
     */
    private String getSign(UcardPayCallbackEntity callDataEntity) {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("orderNo", callDataEntity.getOrderNo());
        map.put("amount", String.valueOf(callDataEntity.getAmount()));
        map.put("internalOrderNo", callDataEntity.getInternalOrderNo());
        map.put("status", String.valueOf(callDataEntity.getStatus()));
        map.put("callBackUrl", callDataEntity.getCallBackUrl());
        map.put("approveDesc", callDataEntity.getApproveDesc());
        String sign = MD5Util.getMD5(MapUtil.getStringSortByKey(map));
        log.info(String.format("回调结果加密处理--请求orderNo:%s,sign string:%s", callDataEntity.getOrderNo(), sign));

        return sign;
    }


    /**
     * 发送验证码
     */
    /*@Override
    public void sendEmailCode(CardSendEmailCodeEntity entity) throws ServiceException {
        //验证邮箱是否存在
        existByEmail(entity.getEmail());

        //构建实体
        SysEmailSendEntity sysEmailSendEntity = cardDepositSendEmailCodeSysEmailEntity(entity);

        //发送收据
        emailService.sendCode(sysEmailSendEntity, sysEmailSendEntity.getMap().get(MapConstants.CODE),
                Constants.EMAIL_REGISTER_VALIDATECODE_TIME * 60 * 1000);
    }*/

    /**
     * 存款发送验证码邮件
     */
    /*private SysEmailSendEntity cardDepositSendEmailCodeSysEmailEntity(CardSendEmailCodeEntity entity) {
        SysEmailSendEntity sysEmailSendEntity = new SysEmailSendEntity();

        Map<String, String> map = new HashMap<>(4);
        String code = GetRandom.getRandom(6);
        map.put(MapConstants.CODE, code);
        Date time = DateUtil.operationMinute(new Date(), Constants.EMAIL_REGISTER_VALIDATECODE_TIME);
        map.put(MapConstants.EXPIRE_TIME, DateUtil.formatTime(time));
        map.put(MapConstants.DATE_TIME, DateUtil.formatTime());

        sysEmailSendEntity.setAddIp(entity.getIp());
        sysEmailSendEntity.setAddTime(entity.getTime());

        sysEmailSendEntity.setUsers(entity.getEmail());
        sysEmailSendEntity.setEmailSendEnum(EmailSendEnum.CARD_DEPOSIT_CODE);
        if (CountryUtil.isCN(entity.getCountry())) {
            sysEmailSendEntity.setTemplateName(SystemEmailCodeConstants.CARD_DEPOSIT_SEND_EMAIL_CODE_CN);
        } else {
            sysEmailSendEntity.setTemplateName(SystemEmailCodeConstants.CARD_DEPOSIT_SEND_EMAIL_CODE_EN);
        }

        sysEmailSendEntity.setMap(map);

        return sysEmailSendEntity;
    }*/

}



