package cn.pluss.platform.job;

import cn.pluss.platform.channel.MchChannelRateNewService;
import cn.pluss.platform.converter.Converter;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.mapper.MerchantRateNewRecordMapper;
import cn.pluss.platform.merchant.MerchantBaseInfoService;
import cn.pluss.platform.merchant.MerchantRateNewRecordService;
import cn.pluss.platform.merchant.MerchantRateNewService;
import cn.pluss.platform.merchantChannelStatus.MerchantChannelStatusService;
import cn.pluss.platform.notice.NoticeService;
import cn.pluss.platform.notice.template.NoticeTemplateService;
import cn.pluss.platform.ryx.RyxConstants;
import cn.pluss.platform.ryx.RyxService;
import cn.pluss.platform.userApp.UserAppService;
import cn.pluss.platform.user.impl.GeneralPushUtil;
import cn.pluss.platform.util.RyxConfig;
import cn.pluss.platform.yinsheng.v20210929.ReqMethod;
import cn.pluss.platform.ys.impl.v20210929.YsConfigV2;
import cn.pluss.platform.ys.impl.v20210929.YsServiceV2;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
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.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ExecutorService;

@Slf4j
@Configuration
@ConditionalOnProperty(prefix = "scheduling", name = "enabled", havingValue = "true")
public class RateChangeNewJob {

    public static final int MAX_TIMES = 10;

    @Autowired
    private GeneralPushUtil generalPushUtil;

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

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

    @Autowired
    private MerchantBaseInfoService mbiService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantRateNewService rateNewService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantRateNewRecordMapper rateNewRecordMapper;

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

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

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

    @Setter(onMethod_ = {@Autowired})
    private MerchantRateNewRecordService rateNewRecordService;

    @Setter(onMethod_ = {@Autowired})
    private MchChannelRateNewService sxfChangeRateNewService;

    @Autowired
    private NoticeTemplateService nTempService;

    @Autowired
    private NoticeService noticeService;

    @Autowired
    private ExecutorService executorService2;

    @Autowired
    private MerchantRateNewRecordService mrnrService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private YsServiceV2 ysServiceV2;

    /**
     * 随行付定时任务
     */
    @Scheduled(cron = "0 0 0 * * ? ")
    public void process2() {

        List<MerchantRateNewRecord> rateNewRecordList = rateNewRecordMapper.selectSxfRateChangeList();

        for (MerchantRateNewRecord rateNewRecord : rateNewRecordList) {
            executorService2.execute(() -> {
                String merchantId = rateNewRecord.getMerchantId();
                LambdaQueryWrapper<MerchantRateNew> qWrapper = Wrappers.lambdaQuery();
                qWrapper.eq(MerchantRateNew::getMerchantId, merchantId)
                        .eq(MerchantRateNew::getChannel, rateNewRecord.getChannel());

                 MerchantRateNew one = rateNewService.getOne(qWrapper);
                if (one == null) {
                    one = sxfChangeRateNewService.getDefaultRate();
                }

                Converter.INSTANCE.cp(rateNewRecord, one);
                rateNewRecord.setStatus("1");

                // 获取用户id
                LambdaQueryWrapper<MerchantChannelStatus> qWrapper2 = Wrappers.lambdaQuery();
                qWrapper2.eq(MerchantChannelStatus::getMerchantId, merchantId)
                        .eq(MerchantChannelStatus::getChannel, rateNewRecord.getChannel());
                MerchantChannelStatus mcs = mcsService.getOne(qWrapper2);

                List<String> aliasList = new ArrayList<>();

                LambdaQueryWrapper<UserApp> qWrapper3 = Wrappers.lambdaQuery();
                qWrapper3.eq(UserApp::getMerchantCode, mcs.getMerchantCode());
                qWrapper3.eq(UserApp::getUserType, "promoter");
                UserApp ua = userAppService.getOne(qWrapper3);
                aliasList.add(ua.getUserId() + "");

                LambdaQueryWrapper<MerchantBaseInfo> qWrapper6 = Wrappers.lambdaQuery();
                qWrapper6.eq(MerchantBaseInfo::getMerchantCode, mcs.getMerchantCode());
                MerchantBaseInfo mbi = mbiService.getOne(qWrapper6);

                // 获取上级用户id
                UserApp uaParent = null;
                if (ua.getParentId() != null) {
                    LambdaQueryWrapper<UserApp> qWrapper4 = Wrappers.lambdaQuery();
                    qWrapper4.eq(UserApp::getUserId, ua.getParentId());
                    uaParent = userAppService.getOne(qWrapper4);
                    aliasList.add(uaParent.getUserId() + "");
                }

                // 获取通知模板
                NoticeTemplate template = nTempService.getNoticeTemplateByType("14");
                String templateContent;
                if (template == null) {
                    templateContent = "尊敬的商户“$1”，您的交易费率调整审核已通过，费率修改记录在个人页面【商户认证】-【商户费率】-右上角【变更记录】中查看，如有疑问请咨询您的业务员。";
                } else {
                    templateContent = template.getContent();
                }
                templateContent = templateContent.replace("$1", mbi.getAlias());

                List<Notice> noticeList = new ArrayList<>();

                Notice notice = new Notice(1, -1, ua.getUserId() + "", ua.getUserName());
                notice.setConrtent(templateContent);
                notice.setDesc(templateContent);
                notice.setTitle("费率修改通知");
                noticeList.add(notice);

                if (uaParent != null) {
                    Notice notice2 = new Notice(1, -1, uaParent.getUserId() + "", uaParent.getUserName());
                    notice2.setConrtent(templateContent);
                    notice2.setDesc(templateContent);
                    notice2.setTitle("费率修改通知");
                    noticeList.add(notice2);
                }

                // 开启事务
                DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                TransactionStatus status = platformTransactionManager.getTransaction(def);
                try {
                    rateNewRecordService.updateById(rateNewRecord);
                    rateNewService.saveOrUpdate(one);
                    noticeService.saveBatch(noticeList);

                    generalPushUtil.sendAllPlatByAlias(aliasList, "费率修改通知", templateContent, "1");
                } catch (Exception e) {
                    platformTransactionManager.rollback(status);
                }

                platformTransactionManager.commit(status);
            });
        }
    }


    /**
     * 瑞银信定时任务
     */
    @Scheduled(cron = "0 1 2 * * ?")
    public void process() {
        List<MerchantRateNewRecord> merchantRates = rateNewRecordMapper.selectRyxRateChangeList();
        for (MerchantRateNewRecord rateNewRecord : merchantRates) {
            executorService2.execute(() -> {

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

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

                // 开启事务
                DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                TransactionStatus status = platformTransactionManager.getTransaction(def);

                try {
                    if (result) {
                        mrnrService.onSuccess(rateNewRecord);
                    } else {
                        mrnrService.onFail(rateNewRecord);
                    }
                    platformTransactionManager.commit(status);
                } catch (Exception e) {
                    e.printStackTrace();
                    platformTransactionManager.rollback(status);
                }
            });
        }
    }

    /**
     * 银盛-云商服，商户修改费率
     */
    @Scheduled(fixedDelay = 3 * 60 * 1000)
    public void checkYsMerchRateStatus() {
        LambdaQueryWrapper<MerchantRateNewRecord> qWrapper = Wrappers.lambdaQuery();
        qWrapper.eq(MerchantRateNewRecord::getStatus, MerchantRateNewRecord.STATUS_IN_REVIEW)
                .eq(MerchantRateNewRecord::getChannel, 4)
                .last("limit " + CheckMerchAuditStatusJob.MAX_SIZE);

        List<MerchantRateNewRecord> editList = mrnrService.list(qWrapper);

        for (MerchantRateNewRecord mrnr : editList) {
            try {
                MerchantChannelStatus mcs = new MerchantChannelStatus();
                mcs.setMerchantId(mrnr.getMerchantId()).setChannel(4);
                mcs = mcsService.getOne(new QueryWrapper<>(mcs));
                if (!MerchantChannelStatus.isAudited(mcs)) {
                    throw new MsgException("商户状态错误");
                }

                String changeFlowId = mrnr.getRemark();

                if (StringUtils.isEmpty(changeFlowId)) {
                    continue;
                }

                JSONObject param = new JSONObject();
                param.put("changeFlowId", changeFlowId);

                JSONObject result;
                try {
                    result = ysServiceV2.req(YsConfigV2.MER_EDIT_RESULT, ReqMethod.MERCHANT_EDIT_RESULT, param);
                } catch (Exception e) {
                    continue;
                }

                transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                    @Override
                    protected void doInTransactionWithoutResult(TransactionStatus status) {

                        String modifyType = result.getString("modifyType");

                        if ("03".equals(modifyType)) {
                            if ("02".equals(result.getString("status"))) {
                                mrnrService.onSuccess(mrnr);
                            }

                            if ("90".equals(result.getString("status"))) {
                                mrnrService.onFail(mrnr);
                            }
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void changeRate(MerchantRateNewRecord rateNewRecord) {
        LambdaQueryWrapper<MerchantChannelStatus> qWrapper = new LambdaQueryWrapper<MerchantChannelStatus>()
                .eq(MerchantChannelStatus::getMerchantId, rateNewRecord.getMerchantId())
                .eq(MerchantChannelStatus::getChannel, rateNewRecord.getChannel());
        MerchantChannelStatus mcs = mcsService.getOne(qWrapper);
        UserApp userApp = new UserApp();
        userApp.setMerchantCode(mcs.getMerchantCode());
        userApp.setUserType("promoter");
        userApp = userAppService.queryUserApp(userApp);

        String merchantCode = userApp.getMerchantCode();

        MerchantRateNew transRateNew = Converter.INSTANCE.trans(rateNewRecord);
        MerchantRateNew.setRateValue(transRateNew);

        MerchantChannelStatus channelStatus = mcsService.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, transRateNew.getBankRateLargeValue().setScale(3, RoundingMode.HALF_UP).divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP).toPlainString());
        map.put(RyxConstants.DEBIT_TOP, 80);
        map.put(RyxConstants.CREDIT_RATE, transRateNew.getBankRateLargeValue().setScale(3, RoundingMode.HALF_UP).divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP).toPlainString());
        map.put(RyxConstants.QR_CREDIT_RATE, transRateNew.getBankRateValue().divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP).toPlainString());
        map.put(RyxConstants.QR_DEBIT_RATE, transRateNew.getBankRateValue().divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP).toPlainString());
        map.put(RyxConstants.WX_DEBIT_RATE, transRateNew.getWxRateValue().divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP).toPlainString());
        map.put(RyxConstants.ZFB_DEBIT_RATE, transRateNew.getAliRateValue().divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP).toPlainString());

        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());
        }
    }
}
