package org.springblade.modules.app.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.czb.gateway.api.APIConstance;
import com.czb.gateway.api.APITools;
import com.czb.gateway.api.KeyStoreUtil;
import com.wn.common.validator.Validator;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.app.common.dto.UserDTO;
import org.springblade.modules.app.constant.ErrorCode;
import org.springblade.modules.app.entity.PaymentAccount;
import org.springblade.modules.app.entity.PaymentAccountApplyment;
import org.springblade.modules.app.entity.PaymentOrderRecord;
import org.springblade.modules.app.service.*;
import org.springblade.modules.app.utils.UserUtils;
import org.springblade.modules.app.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class PayServiceImpl implements IPayService {

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private IPaymentOrderRecordService paymentOrderRecordService;

    @Autowired
    private IPaymentAccountApplymentService paymentAccountApplymentService;

    @Autowired
    private IPaymentAccountService paymentAccountService;

    @Autowired
    private BladeRedis bladeRedis;

    @Autowired
    private ISmartPayService smartPayService;

    @Override
    public Boolean sendSms(String mobile, Integer type) {
        String serialNo = smartPayService.sendSms(mobile, String.valueOf(type));
        if (StringUtil.isEmpty(serialNo)) {
            return false;
        }
        bladeRedis.setEx("code_" + mobile + "_" + type, serialNo, 300L);
        return true;
    }

    @Override
    @Transactional
    public Boolean signAccount(SignContractVo signContractVo) {
        UserDTO user = userUtils.getUser(signContractVo.getToken());
        Validator.notNull(user, ErrorCode.USER_IS_NOT_REGISTERED);
//        Validator.isTrue(user.getType().equals(2), ErrorCode.USER_PERMISSION);
        String mobileSerial = bladeRedis.get("code_" + signContractVo.getMobile() + "_4");
        Validator.notNull(mobileSerial, ErrorCode.USER_SMS_CODE_ERROR);
        signContractVo.setMobileSerial(mobileSerial);
        signContractVo.setDailyLimit("0");
        signContractVo.setTotalLimit("0");
        signContractVo.setSingleLimit("0");
        signContractVo.setStartDate(DateUtil.format(new Date(), "yyyyMMdd"));
        signContractVo.setEndDate("99991231");

        PaymentAccount exist = paymentAccountService.getOne(Wrappers.<PaymentAccount>lambdaQuery()
                .eq(PaymentAccount::getUserId, user.getId())
                .eq(PaymentAccount::getCreditName, signContractVo.getBankNo())
                .eq(PaymentAccount::getCreditNumber, signContractVo.getAccountNo()));
        Validator.isNull(exist, ErrorCode.ACCOUNT_EXISTS);

        PaymentAccountApplyment paymentAccountApplyment = new PaymentAccountApplyment();
        paymentAccountApplyment.setAccountName(signContractVo.getAccountName());
        paymentAccountApplyment.setBankAccount(signContractVo.getAccountNo());
        paymentAccountApplyment.setMobile(signContractVo.getMobile());
        paymentAccountApplyment.setChannel(10);
        paymentAccountApplyment.setIdCard(signContractVo.getIdentityNo());
        paymentAccountApplyment.setUserId(user.getId());
        paymentAccountApplyment.setUserType(user.getType());
        paymentAccountApplyment.setTrueName(signContractVo.getAccountName());
        paymentAccountApplyment.setBusinessName("代收协议签约");
        paymentAccountApplyment.setBank(signContractVo.getBankNo().toString());
        paymentAccountApplyment.setMerchantName(APITools.nvl(APIConstance.getConfig("merId")));
        paymentAccountApplymentService.save(paymentAccountApplyment);

        String collectionSerial = smartPayService.accountSign(signContractVo);
        Validator.notNull(collectionSerial, ErrorCode.SIGN_ACCOUNT_FAIL);

        PaymentAccount paymentAccount = new PaymentAccount();
        paymentAccount.setUserId(user.getId());
        paymentAccount.setAccountType(user.getType());
        paymentAccount.setAccountCode(collectionSerial);
        paymentAccount.setBusinessName("代收");
        paymentAccount.setAccountType(20);
        paymentAccount.setIdCard(signContractVo.getIdentityNo());
        paymentAccount.setMobile(signContractVo.getMobile());
        paymentAccount.setCreditName(signContractVo.getBankNo());
        paymentAccount.setCreditNumber(signContractVo.getAccountNo());
        paymentAccount.setAccountName(signContractVo.getAccountName());
        paymentAccountService.save(paymentAccount);

        return true;
    }

    @Override
    @Transactional
    public Boolean cancelAccount(SignContractVo signContractVo) {

        UserDTO user = userUtils.getUser(signContractVo.getToken());
        Validator.notNull(user, ErrorCode.USER_IS_NOT_REGISTERED);

        PaymentAccount paymentAccount = paymentAccountService.getById(signContractVo.getAccountId());
        Validator.notNull(paymentAccount, ErrorCode.CHANNEL_CODE_NULL);

        PaymentAccountApplyment paymentAccountApplyment = new PaymentAccountApplyment();
        paymentAccountApplyment.setAccountName(paymentAccount.getAccountName());
        paymentAccountApplyment.setBankAccount(paymentAccount.getCreditNumber());
        paymentAccountApplyment.setMobile(paymentAccount.getMobile());
        paymentAccountApplyment.setChannel(11);
        paymentAccountApplyment.setUserId(user.getId());
        paymentAccountApplyment.setUserType(user.getType());
        paymentAccountApplyment.setTrueName(paymentAccount.getAccountName());
        paymentAccountApplyment.setBusinessName("代收协议解约");
        paymentAccountApplyment.setBank(paymentAccount.getCreditName().toString());
        paymentAccountApplyment.setMerchantName(APITools.nvl(APIConstance.getConfig("merId")));
        paymentAccountApplymentService.save(paymentAccountApplyment);

        String mobileSerial = bladeRedis.get("code_" + paymentAccount.getMobile() + "_5");
        Validator.notNull(mobileSerial, ErrorCode.USER_SMS_CODE_ERROR);

        signContractVo.setAccountSerial(paymentAccount.getAccountCode());
        signContractVo.setMobileSerial(mobileSerial);
        Boolean flag = smartPayService.accountCancel(signContractVo);

        Validator.isTrue(flag, ErrorCode.CANCEL_ACCOUNT_FAIL);

        paymentAccount.setIsDeleted(1);
        paymentAccountService.saveOrUpdate(paymentAccount);

        return flag;
    }

    @Override
    @Transactional
    public String quickPayOrder(SmartPayVo smartPayVo) {
        UserDTO user = userUtils.getUser(smartPayVo.getToken());
        Validator.notNull(user, ErrorCode.USER_IS_NOT_REGISTERED);

        PaymentAccount payerAcount = paymentAccountService.getOne(Wrappers.<PaymentAccount>lambdaQuery()
                .eq(PaymentAccount::getId, smartPayVo.getAccountId()).eq(PaymentAccount::getUserId, user.getId())
                .eq(PaymentAccount::getIsDeleted, 0));

        PaymentAccount payeeAcount = paymentAccountService.getOne(Wrappers.<PaymentAccount>lambdaQuery()
                .eq(PaymentAccount::getUserId, smartPayVo.getReceiptId())
                .eq(PaymentAccount::getIsDeleted, 0));

        Validator.notNull(payerAcount, ErrorCode.ACCOUNT_NOT_EXISTS);
        Validator.notNull(payeeAcount, ErrorCode.ACCOUNT_NOT_EXISTS);

        List<ReceiptVo> receiptVoList = new ArrayList<ReceiptVo>();
        ReceiptVo receiptVo = new ReceiptVo();
        receiptVo.setReceiptAmount(smartPayVo.getAmount().toString());
        receiptVo.setReceiptType(0);
        receiptVo.setReceiptAccountName(payeeAcount.getAccountName());
        receiptVo.setReceiptAccountNo(payeeAcount.getCreditNumber());
        receiptVo.setReceiptAccountBranchNo(payeeAcount.getCreditName().toString());
        receiptVo.setReceiptType(payeeAcount.getPayType());
        receiptVoList.add(receiptVo);

        String tradeNo = generateNo();
        smartPayVo.setReceiptVo(receiptVoList);
        smartPayVo.setCollectionSerial(payerAcount.getAccountCode());

        smartPayVo.setTradeNo(tradeNo);

        PaymentOrderRecord paymentOrderRecord = new PaymentOrderRecord();
        paymentOrderRecord.setTradeNo(tradeNo);
        paymentOrderRecord.setPayerAccountId(user.getId());
        paymentOrderRecord.setTransactionMethod(payerAcount.getAccountCode());
        paymentOrderRecord.setPayerAccountNum(payerAcount.getCreditNumber());
        paymentOrderRecord.setPayeeAccountId(smartPayVo.getReceiptId());
        paymentOrderRecord.setPayeeAccountNum(payeeAcount.getCreditNumber());
        paymentOrderRecord.setPayStatus(0);
        paymentOrderRecord.setTimeStartPayment(DateUtil.fromDate(new Date()));
        paymentOrderRecord.setPayMoney(Long.valueOf(smartPayVo.getAmount()));
        paymentOrderRecord.setTransactionChannel("浙商银行");
        paymentOrderRecordService.save(paymentOrderRecord);

        smartPayVo.setOrderId(paymentOrderRecord.getId().toString());
        String token = smartPayService.quickPayOrder(smartPayVo);
        Validator.notNull(token, ErrorCode.ORDER_FAIL);

        paymentOrderRecord.setPayStatus(1);
        paymentOrderRecord.setPayOrderCode(token);
        paymentOrderRecordService.saveOrUpdate(paymentOrderRecord);

        return paymentOrderRecord.getId().toString();
    }

    @Override
    public Boolean quickPay(SmartPayVo smartPayVo) {
        UserDTO user = userUtils.getUser(smartPayVo.getToken());
        Validator.notNull(user, ErrorCode.USER_IS_NOT_REGISTERED);

        PaymentOrderRecord paymentOrderRecord = paymentOrderRecordService.getById(smartPayVo.getOrderId());
        Validator.notNull(paymentOrderRecord, ErrorCode.USER_IS_NOT_REGISTERED);

        PaymentAccount paymentAccount = paymentAccountService.getOne(Wrappers.<PaymentAccount>lambdaQuery().eq(PaymentAccount::getAccountCode,paymentOrderRecord.getTransactionMethod()));
        Validator.notNull(paymentAccount, ErrorCode.USER_IS_NOT_REGISTERED);

        String mobileSerial = bladeRedis.get("code_" + paymentAccount.getMobile() + "_7");
        smartPayVo.setMobileSerial(mobileSerial);
        smartPayVo.setMobile(paymentAccount.getMobile());
        smartPayVo.setPayToken(paymentOrderRecord.getPayOrderCode());
        return smartPayService.quickPay(smartPayVo);
    }

    @Override
    public void payNotify(NotifyVo notifyVo) {
        //ip

        String method = notifyVo.getMethod();
        String version = notifyVo.getVersion();
        String date = notifyVo.getDate();
        String sign = notifyVo.getSign();
        String tradeNo = notifyVo.getTradeNo();
        String result = notifyVo.getResult();
        String resultMsg = notifyVo.getResultMsg();
        if ("smartPayNotify".equals(method)) {
            String origin = notifyVo.getMethod() + version + date + tradeNo + result + resultMsg;
            if (KeyStoreUtil.verifySignData(origin, sign) == 0) {
                paymentOrderRecordService.update(Wrappers.<PaymentOrderRecord>lambdaUpdate()
                        .eq(PaymentOrderRecord::getTradeNo, tradeNo)
                        .set(PaymentOrderRecord::getPayStatus, 2));
            }
        }

    }

    @Override
    public void addPayAccount(PaymentAccountVO data) {
        UserDTO user = userUtils.getUser(data.getToken());
        Validator.notNull(user, ErrorCode.USER_IS_NOT_REGISTERED);
        Validator.isTrue(user.getType().equals(3), ErrorCode.ACCOUNT_NOT_PERMIT);
        PaymentAccount paymentAccount = paymentAccountService.getOne(Wrappers.<PaymentAccount>lambdaQuery()
                .eq(PaymentAccount::getUserId,user.getId()));
        Validator.isNull(paymentAccount, ErrorCode.ACCOUNT_EXISTS);
        paymentAccountService.save(paymentAccount);
    }

    @Override
    public List<PaymentAccount> accountList(SmartPayVo smartPayVo) {
        UserDTO user = userUtils.getUser(smartPayVo.getToken());
        Validator.notNull(user, ErrorCode.USER_IS_NOT_REGISTERED);
        return paymentAccountService.list(Wrappers.<PaymentAccount>lambdaQuery().eq(PaymentAccount::getUserId,user.getId())
                .eq(PaymentAccount::getIsDeleted,0));
    }

    private String generateNo(){
		  String t = DateUtil.format(new Date(),"yyyyMMddHHmmss");
		  int x = (int)(Math.random()*900)+100;
		  String serial = t + x;
		  return serial;
	  }

}
