package cn.pluss.platform.job;

import cn.jiguang.common.utils.StringUtils;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.mapper.MerchantRateMapper;
import cn.pluss.platform.merchantChannelStatus.MerchantChannelStatusService;
import cn.pluss.platform.merchantOrder.MerchantOrderService;
import cn.pluss.platform.merchantProfit.MerchantProfitService;
import cn.pluss.platform.realFans.RealFansService;
import cn.pluss.platform.ryx.RyxConstants;
import cn.pluss.platform.ryx.RyxService;
import cn.pluss.platform.service.UnknownExceptionService;
import cn.pluss.platform.userApp.UserAppService;
import cn.pluss.platform.util.RyxConfig;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.*;

/**
 * 瑞银信费率变更请求定时任务
 * @author DJH
 */
@Slf4j
//@Configuration
@ConditionalOnProperty(prefix = "scheduling", name = "enabled", havingValue = "true")
public class RyxRateChangeJob {

    public static final int MAX_TIMES = 10;

    @Setter(onMethod_ = {@Autowired})
    private UserAppService userAppService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantChannelStatusService merchantChannelStatusService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantRateMapper merchantRateMapper;

    @Setter(onMethod_ = {@Autowired})
    private RyxService ryxService;

    @Setter(onMethod_ = {@Autowired})
    private RestTemplate restTemplate;

    @Setter(onMethod_ = {@Autowired})
    private RealFansService realFansService;

    @Setter(onMethod_ = {@Autowired})
    private PlatformTransactionManager platformTransactionManager;

    @Setter(onMethod_ = {@Autowired})
    private MerchantOrderService merchantOrderService;

    @Setter(onMethod_ = {@Autowired})
    private UnknownExceptionService exceptionService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantProfitService profitService;

    /**
     * 定时任务
     */
    @Scheduled(cron = "0 1 2 * * ?")
    public void process() {
        List<MerchantRate> merchantRates = merchantRateMapper.selectRyxRateChangeList();

        int tryTimes;
        boolean result;
        for (MerchantRate merchantRate: merchantRates) {
            // 开启事务
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus status = platformTransactionManager.getTransaction(def);

            result = false;
            tryTimes = 0;
            // 修改请求尝试10次，
            while (!result && tryTimes <= MAX_TIMES) {
                try {
                    tryTimes++;
                    changeRate(merchantRate.getUserId());
                    result = true;
                    log.error("用户 {}, 第{}次瑞银信费率修改成功", merchantRate.getUserId(), tryTimes);
                } catch (Exception e) {
                    result = false;
                    log.error("用户 {}, 第{}次瑞银信费率修改失败\n, {}", merchantRate.getUserId(), tryTimes, e.getMessage());
                }

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            if (result) {
                platformTransactionManager.commit(status);
                continue;
            }

            // 失败
            try {
                onFail(merchantRate);
                platformTransactionManager.commit(status);
            } catch (Exception e2) {
                log.error("费率修改失败, 订单信息回滚失败, 错误原因: ");
                e2.printStackTrace();

                platformTransactionManager.rollback(status);
                exceptionService.save(e2);
            }
        }
    }

    private void changeRate(String userId) {
        UserApp userApp = new UserApp();
        userApp.setUserId(Long.parseLong(userId));
        userApp = userAppService.queryUserApp(userApp);

        String merchantCode = userApp.getMerchantCode();

        MerchantRate merchantRate = new MerchantRate().setUserId(userId);
        merchantRate = merchantRateMapper.selectOne(new QueryWrapper<>(merchantRate));

        if (merchantRate == null) {
            return;
        }

        MerchantChannelStatus channelStatus = merchantChannelStatusService.getByMerchantCode(merchantCode, 3);

        Map<String, Object> map = new HashMap<>();
        map.put(RyxConstants.MER_IN_ID, channelStatus.getExtra().getString(RyxConstants.MER_IN_ID));
        map.put(RyxConstants.ACCESS_ID, RyxConfig.accessId);
        map.put(RyxConstants.DEBIT_RATE, "0.6");
        map.put(RyxConstants.DEBIT_TOP, 20);
        map.put(RyxConstants.CREDIT_RATE, "0.6");
        map.put(RyxConstants.QR_CREDIT_RATE, "0." + Math.max(merchantRate.getRate(), 22));
        map.put(RyxConstants.QR_DEBIT_RATE, "0." + Math.max(merchantRate.getRate(), 22));
        map.put(RyxConstants.WX_DEBIT_RATE, "0." + merchantRate.getRate());
        map.put(RyxConstants.ZFB_DEBIT_RATE, "0." + merchantRate.getRate());

        log.info("请求参数：{}", JSON.toJSONString(map));

        RyxAccessModel ryxAccessModel = ryxService.accessCombineEncrypt(map, null, RyxConfig.accessId, RyxConfig.accessPubKey);

        MultiValueMap<String, Object> reqMap = RyxAccessModel.toMap(ryxAccessModel);

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(reqMap);

        RyxAccessModel respModel = restTemplate.postForObject(RyxConfig.changeRate, httpEntity, RyxAccessModel.class);

        RyxAccessResp resp = ryxService.accessResultDecrypt(respModel, RyxAccessResp.class);

        if (resp.getCode().equals(RyxAccessResp.RESULT_ERROR)) {
            throw new MsgException(resp.getMsg());
        }
    }

    /**
     * <h1>修改费率失败</h1>
     * <p>
     *     修改费率失败时，<br/>
     *     将费率信息进行回滚 <br/>
     *     重新计算今日已经发生的订单费率、手续费、分润等
     * </p>
     * @param merchantRate
     */
    private void onFail(MerchantRate merchantRate) {
        // 费率改回原来的费率
        merchantRate.setRate(merchantRate.getPreviousRate());
        merchantRateMapper.updateById(merchantRate);

        // 查询当天所有的订单，重新修改订单信息
        UserApp userApp = new UserApp().setUserId(Long.parseLong(merchantRate.getUserId()));
        userApp = userAppService.queryUserApp(userApp);

        MerchantOrder merchantOrder = new MerchantOrder();
        merchantOrder.setStatus("1");
        
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date startTime = calendar.getTime();

        merchantOrder.setStartTime(startTime);
        merchantOrder.setEndTime(new Date());
        merchantOrder.setMerchantCode(userApp.getMerchantCode());

        List<MerchantOrder> orderList = merchantOrderService.list(new QueryWrapper<>(merchantOrder));
        MathContext mc = new MathContext(2, RoundingMode.HALF_UP);
        for (MerchantOrder order: orderList) {
            // 修改订单费率以及订单到账金额
            order.setRate(new BigDecimal(merchantRate.getRate()));
            BigDecimal consumeFee = BigDecimal.valueOf(order.getConsumeFee());
            BigDecimal charge = consumeFee.multiply(BigDecimal.valueOf(merchantRate.getRate())).divide(BigDecimal.valueOf(10000), mc);
            BigDecimal enterFee = consumeFee.subtract(charge);
            order.setEnterFee(enterFee.doubleValue());

            BigDecimal marketAmt = merchantOrder.getMarketAmt();
            // 如果有费率补贴，则修改费率补贴的值
            if (!marketAmt.equals(BigDecimal.ZERO)) {
                merchantOrder.setMarketAmt(charge);
            }

            merchantOrderService.save(merchantOrder);

            MerchantProfit merchantProfit = new MerchantProfit();
            String orderNumber = merchantOrder.getOrderNumber();
            if (StringUtils.isNotEmpty(orderNumber)) {
                merchantProfit.setOrderNumber(orderNumber);
                // 删除现有分润记录
                profitService.remove(new QueryWrapper<>(merchantProfit));
                // 生成分润
                profitService.createOrderProfitV2(merchantOrder,"1");
            }
        }
    }
}
