package com.zanxiang.game.back.serve.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.sd4324530.jtuple.Tuple2;
import com.zanxiang.game.back.base.ServerInfo;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrder;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrderSplitLog;
import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
import com.zanxiang.game.back.serve.service.IGameTencentAppApiBackLogService;
import com.zanxiang.game.back.serve.service.IGameTencentAppApiOrderService;
import com.zanxiang.game.back.serve.service.IGameTencentAppApiOrderSplitLogService;
import com.zanxiang.module.redis.service.IDistributedLockComponent;
import com.zanxiang.module.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 头条订单拆分回传任务
 */
@Slf4j
@Component
public class TencentAppApiOrderSplitBackTask {
    public static final String KEY = ServerInfo.SERVER_NAME + ":tencentAppApiOrderSplitBack:";

    @Autowired
    private IGameTencentAppApiOrderService gameTencentAppApiOrderService;
    @Autowired
    private IGameTencentAppApiOrderSplitLogService gameTencentAppApiOrderSplitLogService;

    @Autowired
    private IDistributedLockComponent distributedLockComponent;
    @Autowired
    private IGameTencentAppApiBackLogService gameTencentAppApiBackLogService;

    @Scheduled(cron = "0 * * * * ?")
    public void execute() {
        LocalDateTime now = LocalDateTime.now().withSecond(0).withNano(0);
        if (!distributedLockComponent.doLock(KEY + DateUtil.formatLocalDateTime(now))) {
            return;
        }
        List<GameTencentAppApiOrderSplitLog> orderSplitLogList = gameTencentAppApiOrderSplitLogService.list(new LambdaQueryWrapper<GameTencentAppApiOrderSplitLog>()
                .in(GameTencentAppApiOrderSplitLog::getBackDay, Arrays.asList(LocalDate.now().minusDays(1), LocalDate.now()))
                .lt(GameTencentAppApiOrderSplitLog::getBackTime, now.plusMinutes(1))
                .eq(GameTencentAppApiOrderSplitLog::getBackStatus, BackStatusEnum.NO.getBackStatus())
                .orderByAsc(GameTencentAppApiOrderSplitLog::getOrderNo)
                .orderByAsc(GameTencentAppApiOrderSplitLog::getBackTime)
        );
        if (CollectionUtils.isEmpty(orderSplitLogList)) {
            return;
        }
        log.error("准备回传分拆订单：{}", orderSplitLogList.size());
        List<GameTencentAppApiOrder> orderList = gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                .in(GameTencentAppApiOrder::getOrderId, orderSplitLogList.stream().map(GameTencentAppApiOrderSplitLog::getOrderNo).collect(Collectors.toSet()))
        );
        Map<String, GameTencentAppApiOrder> orderMap = new HashMap<>(orderList.size());
        orderList.forEach(order -> orderMap.put(order.getOrderId(), order));

        orderSplitLogList.forEach(orderSplitLog -> {
            callback(orderMap.get(orderSplitLog.getOrderNo()), orderSplitLog);
        });
    }

    private void callback(GameTencentAppApiOrder order, GameTencentAppApiOrderSplitLog orderSplitLog) {
        log.error("开始回传拆分订单：{}-{}", orderSplitLog.getOrderNo(), orderSplitLog.getBackIndex());
        try {
            Tuple2<BackStatusEnum, String> backResult = gameTencentAppApiOrderService.doCallback(order, orderSplitLog.getBackTime(), orderSplitLog.getSplitMoney());
            gameTencentAppApiOrderSplitLogService.update(new LambdaUpdateWrapper<GameTencentAppApiOrderSplitLog>()
                    .set(GameTencentAppApiOrderSplitLog::getExecuteTime, LocalDateTime.now())
                    .set(GameTencentAppApiOrderSplitLog::getBackStatus, backResult.first.getBackStatus())
                    .set(GameTencentAppApiOrderSplitLog::getBackErrorMsg, backResult.second)
                    .eq(GameTencentAppApiOrderSplitLog::getId, orderSplitLog.getId())
            );
            if (backResult.first == BackStatusEnum.SUCCESS) {
                gameTencentAppApiOrderService.update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                        .set(GameTencentAppApiOrder::getIsBack, backResult.first.getBackStatus())
                        .eq(GameTencentAppApiOrder::getId, order.getId())
                );
            } else {
                gameTencentAppApiOrderService.update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                        .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS_PART.getBackStatus())
                        .eq(GameTencentAppApiOrder::getId, order.getId())
                );
            }
            log.error("订单回传完成：{}-{}, {}-{}", orderSplitLog.getOrderNo(), orderSplitLog.getBackIndex(), backResult.first, backResult.second);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            try {
                gameTencentAppApiOrderSplitLogService.update(new LambdaUpdateWrapper<GameTencentAppApiOrderSplitLog>()
                        .set(GameTencentAppApiOrderSplitLog::getExecuteTime, LocalDateTime.now())
                        .set(GameTencentAppApiOrderSplitLog::getBackStatus, BackStatusEnum.FAILED.getBackStatus())
                        .set(GameTencentAppApiOrderSplitLog::getBackErrorMsg, e.getMessage())
                        .eq(GameTencentAppApiOrderSplitLog::getId, orderSplitLog.getId())
                );
                gameTencentAppApiOrderService.update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                        .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS_PART.getBackStatus())
                        .eq(GameTencentAppApiOrder::getId, order.getId())
                );
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }
    }
}
