package com.izouma.nineth.service.pay;

import com.izouma.nineth.config.GeneralProperties;
import com.izouma.nineth.config.RedisKeys;
import com.izouma.nineth.config.SysConstants;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.pay.*;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.lock.RedisLockable;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.service.AdapayMerchantService;
import com.izouma.nineth.service.SysConfigService;
import com.izouma.nineth.service.realname.RealNameLogService;
import com.izouma.nineth.utils.DateTimeUtils;
import com.izouma.nineth.utils.IPUtils;
import com.izouma.nineth.utils.IdentityUtil;
import com.izouma.nineth.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 支付适配
 */
@Component
@Slf4j
public class UniformPayUtil {

    @Autowired
    private Map<String, UniformPayService> payServiceMap;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private OrderRepo orderRepo;

    @Autowired
    private PaymentInfoRepo paymentInfoRepo;

    @Autowired
    private UserBankCardRepo userBankCardRepo;

    @Autowired
    private UserRepo userRepo;

    @Autowired
    private PayHelper payHelper;

    @Autowired
    private AdapayMerchantService adapayMerchantService;

    @Autowired
    public RedisTemplate redisTemplate;

    @Autowired
    private RealNameLogService realNameLogService;

    @Autowired
    private TransferMoneyInfoRepo transferMoneyInfoRepo;

    @Autowired
    private DivMoneyRepo divMoneyRepo;

    @Autowired
    private GiftOrderRepo giftOrderRepo;

    @Autowired
    private AssetRepo assetRepo;

    @Autowired
    private GeneralProperties generalProperties;


    @Autowired
    private IdentityUtil identityUtil;

    /**
     * 获取默认支付平台
     *
     * @return
     */
    public String getDefaultPayPlatform() {
        String payPlatform = null;
        try {
            payPlatform = sysConfigService.getString(SysConstants.PAY_PLATFORM);
        } catch (Exception e) {
            log.error("获取配置失败：" + SysConstants.PAY_PLATFORM + ", 原因：" + e.getMessage());
        }
        return payPlatform;
    }

    /**
     * 获取二手交易支付平台
     *
     * @return
     */
    public String getSecondHandPayPlatform() {
        String payPlatform = null;
        try {
            payPlatform = sysConfigService.getString(SysConstants.SECOND_HAND_PAY_PLATFORM);
        } catch (Exception e) {
            log.error("获取配置失败：" + SysConstants.SECOND_HAND_PAY_PLATFORM + ", 原因：" + e.getMessage());
        }
        return payPlatform;
    }

    /**
     * 获取转赠支付平台切换
     *
     * @return
     */
    public String getGiftHandPayPlatform() {
        String payPlatform = null;
        try {
            payPlatform = sysConfigService.getString(SysConstants.GIFT_HAND_PAY_PLATFORM);
        } catch (Exception e) {
            log.error("获取配置失败：" + SysConstants.GIFT_HAND_PAY_PLATFORM + ", 原因：" + e.getMessage());
        }
        return payPlatform;
    }



    /**
     * 选择支付平台
     *
     * @param payPlatform
     * @return
     */
    public UniformPayService select(String payPlatform) {
        UniformPayService payService = payServiceMap.get(payPlatform);
        if (payService == null) {
            //log.warn("支付平台选择失败,未找到：" + payPlatform);
            //payService = payServiceMap.entrySet().iterator().next().getValue();
            //默认自定义的绑卡逻辑
            payService = payServiceMap.get(UniformPayConstants.CUSTOM_PLATFORM);
        }

        return payService;
    }

    /**
     * 锁定支付，防止并发
     *
     * @param request
     * @return
     * @throws Exception
     */
    @RedisLockable(prefix = RedisKeys.ORDER_LOCK, key = "#request.orderId", expiration = 360)
    public UniformPayResult pay(UniformPayRequest request) throws Exception {
        UniformPayResult uniformPayResult;

        //指定了支付平台
        String payPlatform = request.getPayPlatform();

        //统一检查状态
        Long orderId = request.getOrderId();
        String returnUrl = null;
        BigDecimal payAmt = null;
        OrderStatus orderStatus = null;
        if(orderId != null){

            Order order = orderRepo.findByIdAndDelFalse(orderId).orElseThrow(new BusinessException("订单不存在"));
            orderStatus = order.getStatus();
            returnUrl = payHelper.orderDetailUrl(order);

            if (order.getStatus() != OrderStatus.NOT_PAID) {
                //跳转到查看支付结果页面
                uniformPayResult = new UniformPayResult();
                uniformPayResult.setOrderId(orderId);
                uniformPayResult.setOrderStatus(orderStatus);
                uniformPayResult.setPayUrl(returnUrl);
                uniformPayResult.setReturnUrl(returnUrl);
                return uniformPayResult;
            }

            //二手交易检查
            if(StringUtils.isBlank(payPlatform)){
                if (order.getSource() == CollectionSource.TRANSFER) {
                    payPlatform = getSecondHandPayPlatform();
                }
            }

            payAmt = order.getTotalPrice();
        }

        //转赠订单
        Long giftOrderId = request.getGiftOrderId();
        if(giftOrderId != null){
            //功能开关判断
            boolean isOpen = sysConfigService.getBoolean(SysConstants.GIFT_PAY_SWITCH);
            if(!isOpen){
                throw new BusinessException("转赠支付功能未开启");
            }

            GiftOrder order = giftOrderRepo.findById(giftOrderId).orElseThrow(new BusinessException("转赠订单不存在"));
            orderStatus = order.getStatus();
            assetRepo.findById(order.getAssetId()).orElseThrow(new BusinessException("藏品不存在"));
            returnUrl = payHelper.resolveHome(order.getProjectId());

            if (order.getStatus() != OrderStatus.NOT_PAID) {
                //跳转到查看支付结果页面
                uniformPayResult = new UniformPayResult();
                uniformPayResult.setOrderStatus(order.getStatus());
                uniformPayResult.setPayUrl(returnUrl);
                uniformPayResult.setReturnUrl(returnUrl);
                return uniformPayResult;
            }

            //转赠交易检查
            if(StringUtils.isBlank(payPlatform)){
                payPlatform = getGiftHandPayPlatform();
            }

            payAmt = order.getGasPrice();
        }

        if(payAmt == null || payAmt.compareTo(BigDecimal.ZERO) <= 0){
            throw new BusinessException("订单金额错误：" + payAmt);
        }


        if(UniformPayConstants.NOTPAY_PLATFORM.equals(payPlatform)){
            throw new BusinessException("管理员已关闭支付通道，无法支付");
        }

        //默认检查
        if(StringUtils.isBlank(payPlatform)){
            //默认支付平台
            payPlatform = getDefaultPayPlatform();
        }

        UniformPayService payService = select(payPlatform);

        uniformPayResult = payService.pay(request);
        uniformPayResult.setOrderId(orderId);
        uniformPayResult.setGiftOrderId(giftOrderId);
        uniformPayResult.setOrderStatus(orderStatus);
        uniformPayResult.setReturnUrl(returnUrl);
        return uniformPayResult;
    }

    public UniformNotifyResult notify(UniformNotifyRequest request) throws Exception {
        String orderNo = request.getOrderNo();
        PaymentInfo paymentInfo = paymentInfoRepo.findByOrderNo(orderNo).orElseThrow(new BusinessException("支付信息不存在"));
        String payPlatform = paymentInfo.getPayPlatform();

        UniformPayService payService = payServiceMap.get(payPlatform);
        if (payService == null) {
            throw new BusinessException("不受支持的支付平台：" + payPlatform);
        }

        return payService.notify(request);
    }


    /**
     * 独立的事务，修改数据有效
     *
     * @param orderNo
     * @return
     * @throws Exception
     */
    @Transactional(value = Transactional.TxType.REQUIRES_NEW, rollbackOn = Exception.class)
    public Map<String, Object> refund(String orderNo, String refundReason) throws Exception {
        String payPlatform = null;
        //获取发起支付信息的支付平台
        PaymentInfo paymentInfo = paymentInfoRepo.findByOrderNo(orderNo).orElseThrow(new BusinessException("支付信息不存在"));
        if (paymentInfo.getStatus() != PayStatus.PENDING_REFUND) {
            throw new BusinessException("支付记录不是待退款状态，请核实");
        }

        payPlatform = paymentInfo.getPayPlatform();

        //设置退款中
        paymentInfo.setStatus(PayStatus.REFUNDING);
        paymentInfoRepo.save(paymentInfo);

        UniformPayService payService = payServiceMap.get(payPlatform);
        if (payService == null) {
            throw new BusinessException("不受支持的支付平台：" + payPlatform);
        }

        Map<String, Object> res = payService.refund(orderNo, refundReason);

        return res;
    }

    /**
     * 独立的事务，修改数据有效
     *
     * @return
     * @throws Exception
     */
    @Transactional(value = Transactional.TxType.REQUIRES_NEW, rollbackOn = Exception.class)
    public UniformNotifyResult refundNotify(UniformNotifyRequest request) throws Exception {
        String orderNo = request.getOrderNo();
        PaymentInfo paymentInfo = paymentInfoRepo.findByOrderNo(orderNo).orElseThrow(new BusinessException("支付信息不存在"));
        String payPlatform = paymentInfo.getPayPlatform();

        UniformPayService payService = payServiceMap.get(payPlatform);
        if (payService == null) {
            throw new BusinessException("不受支持的支付平台：" + payPlatform);
        }

        return payService.refundNotify(request);
    }


    /**
     * 独立的事务，修改数据有效
     *
     * @return
     * @throws Exception
     */
    @Transactional(value = Transactional.TxType.REQUIRES_NEW, rollbackOn = Exception.class)
    public UniformNotifyResult transferNotify(UniformNotifyRequest request) throws Exception {
        String tradeNo = request.getOrderNo();
        TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.findByTradeNo(tradeNo)
                .orElseThrow(new BusinessException("请求转账信息不存在"));
        String payPlatform = transferMoneyInfo.getPayPlatform();

        UniformPayService payService = payServiceMap.get(payPlatform);
        if (payService == null) {
            throw new BusinessException("不受支持的支付平台：" + payPlatform);
        }

        UniformNotifyResult result = payService.transferNotify(request);

        //获取更新后的结果，不能报错
        transferMoneyInfo = transferMoneyInfoRepo.findByTradeNo(tradeNo)
                .orElse(null);
        if (transferMoneyInfo != null && transferMoneyInfo.getStatus() == TransferStatus.FAILED) {
            //更新分账记录为失败
            DivMoney divMoney = divMoneyRepo.findById(transferMoneyInfo.getDivMoneyId()).orElse(null);
            if (divMoney != null) {
                divMoney.setStatus(DivStatus.ERROR);
                divMoney.setTransferResult(transferMoneyInfo.getResult());
                divMoneyRepo.save(divMoney);
            }
        }

        return result;
    }




    @Transactional(value = Transactional.TxType.REQUIRES_NEW, rollbackOn = Exception.class)
    public UserBankCard addBankCard(UniformBindBank bindBank) throws Exception {
        Long userId = bindBank.getUserId();
        String bankNo = bindBank.getBankNo();
        String phone = bindBank.getPhone();

        String payPlatform = bindBank.getPayPlatform();
        if(StringUtils.isBlank(payPlatform)){
            //默认支付平台
            payPlatform = getDefaultPayPlatform();
        }

        UniformPayService payService = select(payPlatform);


        //删除旧数据
        userBankCardRepo.softDeleteByUserId(userId);

        UserBankCard userBankCard = payService.addBankCard(bindBank);

        if(UniformPayConstants.LIANLIANPAY_PLATFORM.equals(userBankCard.getPayPlatform())){
            //如果是钱包绑卡，跳过后续验证
            return userBankCard;
        }

        if (sysConfigService.getBoolean(SysConstants.FOUR_ELEMENT_SWITCH)) {
            int count = (Integer) Objects.requireNonNullElse(redisTemplate.opsForValue().get(RedisKeys.BANK_CARD_REAL_NAME_COUNT + userId), 0);
            int idays_count = sysConfigService.getInt((SysConstants.DAYS_FOUR_ELEMENT_COUNT));
            if (count >= idays_count) {
                throw new BusinessException("绑卡次数失败过多，请明天在试");
            }
            count =count+1;
            redisTemplate.opsForValue().set(RedisKeys.BANK_CARD_REAL_NAME_COUNT + userId, count, DateTimeUtils.getRemainSecondsOneDay(new Date()), TimeUnit.SECONDS);
            int restCount = Math.max(idays_count-count,0);
            try {
                identityUtil.verifyInformation(bankNo, phone, userBankCard.getIdNo(), userBankCard.getRealName());
            }catch (BusinessException e){
                throw new BusinessException(e.getMessage() + ",今日还可以尝试" + restCount + "次");
            }

        }else {
            if(!UniformPayConstants.ADAPAY_PLATFORM.equals(payPlatform) && sysConfigService.getBoolean(SysConstants.BINDING_BANK_CARD_SWITCH) ){
                User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
                //前缀隔离
                String memberId = sysConfigService.getString(SysConstants.MEMBER_PREFIX) + user.getId().toString();

                //支付方绑定
                adapayMerchantService.createMemberForAll(memberId, phone,
                        userBankCard.getRealName(), userBankCard.getIdNo());
                String accountId = adapayMerchantService.createSettleAccountForAll
                        (memberId, userBankCard.getRealName(),
                                userBankCard.getIdNo(), userBankCard.getPhone(), userBankCard.getBankNo());
                user.setSettleAccountId(Optional.ofNullable(accountId).orElse("1"));
                userRepo.save(user);
            }
        }

        return userBankCard;

    }


    public void removeBankCard(Long userId) throws Exception {
        String payPlatform = null;
        List<UserBankCard> cardList = userBankCardRepo.findByUserId(userId);
        if (cardList.size() > 0) {
            //找到当时使用的绑卡平台
            payPlatform = cardList.get(0).getPayPlatform();
        }

        UniformPayService payService = null;
        if (StringUtils.isEmpty(payPlatform)) {
            //默认是汇付平台绑卡
            payService = payServiceMap.get(UniformPayConstants.ADAPAY_PLATFORM);
        }

        if (payService == null) {
            payService = select(payPlatform);
        }

        payService.removeBankCard(userId);
        User currentUser = SecurityUtils.getAuthenticatedUser();
        String ipAddr = IPUtils.getIpAddr();
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
        RealNameLog realNameLog = RealNameLog.builder().operatorId(currentUser.getId())
                .operatorName(currentUser.getUsername())
                .operatorIp(ipAddr).changeUserId(user.getId()).changeUserName(cardList.stream().map(UserBankCard::getRealName).filter(StringUtils::isNotBlank)
                        .findFirst().orElse("")).operateType("解除绑卡").idNo(cardList.stream().map(UserBankCard::getIdNo).filter(StringUtils::isNotBlank)
                .findFirst().orElse(""))
                .cardNo(cardList.stream().map(UserBankCard::getBankNo).filter(StringUtils::isNotBlank).collect(Collectors.joining(","))).build();
        realNameLogService.insert(realNameLog);
    }

    /**
     * 检查是否绑卡
     *
     * @param userId
     */
    public boolean isBindBankCard(Long userId) {

        String payPlatform = getDefaultPayPlatform();
        ;

        UniformPayService payService = select(payPlatform);

        return payService.isBindBankCard(userId);

    }

}
