package com.tmerclub.cloud.multishop.service.impl;

import com.alibaba.fastjson2.JSON;
import com.tmerclub.cloud.api.payment.allinpay.order.resp.DepositApplyResp;
import com.tmerclub.cloud.api.payment.allinpay.order.resp.PayByBackSmsResp;
import com.tmerclub.cloud.api.payment.feign.AllinpayFeignClient;
import com.tmerclub.cloud.common.constant.AllinpayConstant;
import com.tmerclub.cloud.common.constant.AllinpayPayStatus;
import com.tmerclub.cloud.common.constant.AllinpayRechargeStatusType;
import com.tmerclub.cloud.common.constant.AllinpayWithdrawCashStatusType;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.constant.DistributedIdKey;
import com.tmerclub.cloud.multishop.constant.ShopWalletAmountType;
import com.tmerclub.cloud.multishop.constant.ShopWalletChangeReason;
import com.tmerclub.cloud.multishop.constant.ShopWalletIoType;
import com.tmerclub.cloud.multishop.dto.AllinpayRechargeDTO;
import com.tmerclub.cloud.multishop.dto.ShopWalletLogSearchDTO;
import com.tmerclub.cloud.multishop.mapper.ShopWalletMapper;
import com.tmerclub.cloud.multishop.mongo.MongoShopWalletLogBO;
import com.tmerclub.cloud.multishop.service.ShopRechargeService;
import com.tmerclub.cloud.multishop.service.ShopWalletLogService;
import com.tmerclub.cloud.multishop.vo.ShopRechargeVO;
import com.mongodb.client.result.UpdateResult;
import org.apache.dubbo.config.annotation.DubboReference;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Objects;

/**
 * 商家充值
 * @author TRACK
 */
@Service
public class ShopRechargeServiceImpl implements ShopRechargeService {
    private static final Logger logger = LoggerFactory.getLogger(ShopRechargeServiceImpl.class);

    @Autowired
    private ShopWalletLogService shopWalletLogService;
    @DubboReference
    private AllinpayFeignClient allinpayFeignClient;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private ShopWalletMapper shopWalletMapper;
    @Autowired
    private SegmentManager segmentManager;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ShopRechargeVO shopRecharge(MongoShopWalletLogBO shopWalletLog, String returnUrl) {
        Long walletLogId = segmentManager.getSegmentId(DistributedIdKey.tmerclub_SHOP_WALLET_LOG);
        shopWalletLog.setWalletLogId(walletLogId);
        // 通联申请
        ServerResponseEntity<?> rechargeApplyResponse = allinpayFeignClient.rechargeApply(
                shopWalletLog.getShopChangeAmount(), shopWalletLog.getShopId(), walletLogId, returnUrl);
        if (!rechargeApplyResponse.isSuccess()) {
            throw new LuckException(rechargeApplyResponse.getMsg());
        }
        DepositApplyResp depositApplyResp = JSON.parseObject(JSON.toJSONString(rechargeApplyResponse.getData()), DepositApplyResp.class);
        shopWalletLog.setBizOrderNo(Long.parseLong(depositApplyResp.getBizOrderNo()));
        // 保存申请日志
        shopWalletLog.setAllinpayStatus(AllinpayRechargeStatusType.APPLY_SUCCESS.value());
        shopWalletLogService.saveMongoBatch(Collections.singletonList(shopWalletLog));
        return new ShopRechargeVO(depositApplyResp.getPayInfo(), walletLogId);
    }

    @Override
    public void confirmRechargePay(AllinpayRechargeDTO rechargeDTO, Long shopId) {
        // 申请充值记录
        ShopWalletLogSearchDTO shopWalletLogQuery = new ShopWalletLogSearchDTO();
        shopWalletLogQuery.setBizOrderNo(Long.valueOf(rechargeDTO.getBizOrderNo()));
        shopWalletLogQuery.setReason(ShopWalletChangeReason.APPLY_RECHARGE.value());
        shopWalletLogQuery.setShopId(shopId);
        shopWalletLogQuery.setShopIoType(ShopWalletIoType.INCOME.value());
        shopWalletLogQuery.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
        MongoShopWalletLogBO rechargeLog = shopWalletLogService.listByParam(shopWalletLogQuery).get(0);
        if (Objects.isNull(rechargeLog)) {
            throw new LuckException("申请充值日志不存在");
        }
        if (!Objects.equals(rechargeLog.getAllinpayStatus(), AllinpayRechargeStatusType.APPLY_SUCCESS.value())
                && !Objects.equals(rechargeLog.getAllinpayStatus(), AllinpayRechargeStatusType.WAIT_PAY.value())) {
            throw new LuckException("申请充值状态异常，请刷新重试");
        }
        ServerResponseEntity<PayByBackSmsResp> payResponse = allinpayFeignClient.payByBackSms(AllinpayConstant.SHOP + shopId, rechargeDTO.getBizOrderNo(), rechargeDTO.getVerificationCode());
        if (!payResponse.isSuccess()) {
            throw new LuckException(payResponse.getMsg());
        }

        PayByBackSmsResp payByBackSmsResp = payResponse.getData();
        String payFailMessage = payByBackSmsResp.getPayFailMessage();
        if (Objects.equals(payByBackSmsResp.getPayStatus(), AllinpayPayStatus.UNPAY.value())) {
            // 修改申请日志
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(rechargeLog.getWalletLogId()));
            Update update = new Update();
            update.set("allinpayStatus", AllinpayWithdrawCashStatusType.WAIT_PAY.value());
            update.set("payFailMessage", payFailMessage);
            mongoTemplate.updateFirst(query, update, MongoShopWalletLogBO.class);
            // 收银宝快捷短信验证码输入错误场景，允许商户继续调用确认支付
            logger.error("充值订单{}充值失败，原因为：{}", payByBackSmsResp.getBizOrderNo(), payFailMessage);
        }
    }

    @Override
    public void resendPaySms(String bizOrderNo, Long shopId) {
        // 申请充值记录
        ShopWalletLogSearchDTO shopWalletLogQuery = new ShopWalletLogSearchDTO();
        shopWalletLogQuery.setBizOrderNo(Long.valueOf(bizOrderNo));
        shopWalletLogQuery.setShopId(shopId);
        shopWalletLogQuery.setReason(ShopWalletChangeReason.APPLY_RECHARGE.value());
        shopWalletLogQuery.setShopIoType(ShopWalletIoType.INCOME.value());
        shopWalletLogQuery.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
        shopWalletLogQuery.setAllinpayStatus(AllinpayWithdrawCashStatusType.WAIT_PAY.value());
        MongoShopWalletLogBO rechargeLog = shopWalletLogService.listByParam(shopWalletLogQuery).get(0);
        if (Objects.isNull(rechargeLog)) {
            throw new LuckException("申请充值日志不存在");
        }
        if (!Objects.equals(rechargeLog.getAllinpayStatus(), AllinpayRechargeStatusType.WAIT_PAY.value())) {
            throw new LuckException("充值申请不在未支付状态，请刷新重试");
        }
        ServerResponseEntity<Void> response = allinpayFeignClient.resendPaySms(bizOrderNo);
        if (!response.isSuccess()) {
            throw new LuckException(response.getMsg());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rechargeBack(String bizOrderNo, String payStatus, String bizUserId) {
        // 申请充值记录
        ShopWalletLogSearchDTO shopWalletLogQuery = new ShopWalletLogSearchDTO();
        shopWalletLogQuery.setBizOrderNo(Long.valueOf(bizOrderNo));
        shopWalletLogQuery.setReason(ShopWalletChangeReason.APPLY_RECHARGE.value());
        shopWalletLogQuery.setShopId(Long.valueOf(bizUserId.substring(AllinpayConstant.SHOP_LENGTH)));
        shopWalletLogQuery.setShopIoType(ShopWalletIoType.INCOME.value());
        shopWalletLogQuery.setAmountType(ShopWalletAmountType.SETTLED_AMOUNT.value());
        MongoShopWalletLogBO rechargeLog = shopWalletLogService.listByParam(shopWalletLogQuery).get(0);
        if (Objects.isNull(rechargeLog)) {
            throw new LuckException("申请充值日志不存在");
        }
        if (Objects.equals(rechargeLog.getAllinpayStatus(), AllinpayRechargeStatusType.RECHARGE_SUCCESS.value())) {
            return;
        }
        if (Objects.equals(rechargeLog.getReason(), ShopWalletChangeReason.SUCCESS_RECHARGE.value())) {
            return;
        }

        Long shopId = rechargeLog.getShopId();
        Long amount = rechargeLog.getShopChangeAmount();
        allinpaySuccess(shopId, rechargeLog, amount);
    }

    private void allinpaySuccess(Long shopId, MongoShopWalletLogBO rechargeLog, Long amount) {
        shopWalletMapper.addSettledAmount(shopId, amount, rechargeLog.getPaySysType(), true);

        // 更新支付状态
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(rechargeLog.getWalletLogId()).and("reason").is(ShopWalletChangeReason.APPLY_RECHARGE.value()));
        Update update = new Update();
        update.set("reason", ShopWalletChangeReason.SUCCESS_RECHARGE.value());
        update.set("allinpayStatus", AllinpayRechargeStatusType.RECHARGE_SUCCESS.value());
        update.set("payFailMessage", "");
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, MongoShopWalletLogBO.class);
        if (updateResult.getModifiedCount() < 1) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }
}
