package com.shkj.wms.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shkj.common.constant.RedisConstant;
import com.shkj.common.core.domain.Result;
import com.shkj.common.utils.DateUtils;
import com.shkj.wcs.third.stacker.StkCallUtil;
import com.shkj.wms.bo.STKMoveBo;
import com.shkj.wms.domain.BusinOutInPlan;
import com.shkj.wms.domain.SysThirdExceptionRequest;
import com.shkj.wms.enums.PlanStatusEnum;
import com.shkj.wms.enums.ThirdApiStatusEnum;
import com.shkj.wms.enums.ThirdApiTypeEnum;
import com.shkj.wms.mapper.SysThirdExceptionRequestMapper;
import com.shkj.wms.service.IBusinOutInPlanService;
import com.shkj.wms.service.IBusinStockMoveDService;
import com.shkj.wms.service.ISysThirdExceptionRequestService;
import com.shkj.wms.utils.WmsCallWcsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 第三方请求异常Service业务层处理
 *
 * @author lch
 * @date 2023-02-02
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class SysThirdExceptionRequestServiceImpl extends ServiceImpl<SysThirdExceptionRequestMapper, SysThirdExceptionRequest> implements ISysThirdExceptionRequestService {
    @Autowired
    private StkCallUtil stkCallUtil;

    @Autowired
    private WmsCallWcsUtil callOutStock;

    @Autowired
    @Lazy
    private IBusinOutInPlanService businOutInPlanService;

    @Autowired
    @Lazy
    private IBusinStockMoveDService businStockMoveDService;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public Result executeException(String taskCode) throws InterruptedException {

        SysThirdExceptionRequest request = getOne(new LambdaQueryWrapper<SysThirdExceptionRequest>()
                .eq(SysThirdExceptionRequest::getCode, taskCode)
                .eq(SysThirdExceptionRequest::getStatus, ThirdApiStatusEnum.fail.getValue())
                .last("limit 1").orderByDesc(SysThirdExceptionRequest::getCreateTime));

        log.info("executeException = {}", request);
        if (request == null) {
            return Result.err().msg("不存在异常信息");
        }

        String type = request.getType();
        Result result;
        switch (type) {
            case ThirdApiTypeEnum.wcsOutTask:
            case ThirdApiTypeEnum.wcsCallOutStock:
                STKMoveBo vo = JSONObject.parseObject(request.getRequestBody(), STKMoveBo.class);
                vo.setLayer(request.getLayer());
                Result runTask = businOutInPlanService.checkIsRunTask(vo.getTaskId());
                if (Result.isOk(runTask)) {
                    result = runTask;
                    log.info("不需要下发任务时，该单据状态为完成：" + taskCode);
                    Result<BusinOutInPlan> businOutInPlanResult = businOutInPlanService.wcsGetPlanByOrderNo(taskCode);
                    BusinOutInPlan businOutInPlan = businOutInPlanResult.getData();
                    if (businOutInPlan.getPlanStatus().equals(PlanStatusEnum.WAIT.getValue())){
                        businOutInPlan.setPlanStatus(PlanStatusEnum.DOING.getValue());
                        businOutInPlanService.updateById(businOutInPlan);
                    }else {
                        log.info("下发出库任务时，完成出库状态不是带出库，不需要修改");
                    }
                } else {
                    result = stkCallUtil.outTask(vo);
                    if (Result.isOk(result)) {
                        Result<BusinOutInPlan> businOutInPlanResult = businOutInPlanService.wcsGetPlanByOrderNo(taskCode);
                        if(Result.isOk(businOutInPlanResult)){
                            BusinOutInPlan businOutInPlan = businOutInPlanResult.getData();
                            businOutInPlan.setPlanStatus(PlanStatusEnum.DOING.getValue());
                            businOutInPlanService.updateById(businOutInPlan);
                        }
                        log.info("呼叫出库任务下发成功：" + vo);
                    } else {
                        log.info("呼叫出库任务下发失败：" + vo);
                    }

                }
                break;
            case ThirdApiTypeEnum.wcsMoveLocationTask:
                STKMoveBo moveBo = JSONObject.parseObject(request.getRequestBody(), STKMoveBo.class);
                result = stkCallUtil.locationAdjustment(moveBo);
                break;
            default:
                log.info("type = {}", type);
                return Result.err().msg("类型异常");
        }

        if (!Result.isOk(result)) {
            log.info("定时任务处理异常结果 result = {}", result);
            return result;
        }
        //更新数据
        log.info("定时任务更新数据 = {}", request);
        request.setStatus(ThirdApiStatusEnum.success.getValue());
        request.setUpdateTime(DateUtils.getNowDate());
        this.updateById(request);

        updatePlanStatusByAgain(type, taskCode);
        return Result.ok();
    }

    /**
     * 状态更新计划
     *
     * @param type     类型
     * @param taskCode 任务代码
     */
    private void updatePlanStatusByAgain(String type, String taskCode) {
        switch (type) {
            case ThirdApiTypeEnum.wcsOutTask:
                businOutInPlanService.updatePlanStatusByAgain(taskCode);
                break;
            case ThirdApiTypeEnum.wcsMoveLocationTask:
                businStockMoveDService.updateMoveStatusByAgain(taskCode);
                break;
            default:
                log.info("type = {}", type);
        }
    }


    @Override
    public void addException(String code, String type, String requestBody, String responseBody, Boolean isSuccess, Date planTime,Integer layer) {
        SysThirdExceptionRequest request = new SysThirdExceptionRequest();
        request.setCode(code);
        request.setType(type);
        request.setStatus(isSuccess ? ThirdApiStatusEnum.success.getValue() : ThirdApiStatusEnum.fail.getValue());
        request.setRequestBody(requestBody);
        request.setResponseBody(responseBody);
        request.setCreateBy("admin").setCreateTime(new Date());
        request.setPlanTime(planTime);
        request.setUpdateTime(DateUtils.getNowDate());
        request.setLayer(layer);
        this.save(request);
    }

    @Override
    public List<SysThirdExceptionRequest> getListByTaskIdAndOrderNo(Long taskId, String orderNo) {
        LambdaQueryWrapper<SysThirdExceptionRequest> eq = new LambdaQueryWrapper<SysThirdExceptionRequest>().eq(SysThirdExceptionRequest::getTaskId, taskId)
                .eq(SysThirdExceptionRequest::getOrderNo, orderNo);
        return list(eq);
    }

    @Override
    public SysThirdExceptionRequest getOneByOrderNo(String orderNo) {
        SysThirdExceptionRequest oneByOrderNo = this.baseMapper.getOneByOrderNo(orderNo);
        return oneByOrderNo;
    }


    /**
     * 得到第三异常请求列表
     *
     * @return {@code List<SysThirdExceptionRequest>}
     */
    public List<SysThirdExceptionRequest> getThirdExceptionRequestList() {
        LambdaQueryWrapper<SysThirdExceptionRequest> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(SysThirdExceptionRequest::getCreateTime);
        wrapper.last("limit 20");
        return list(wrapper);
    }

    /**
     * 做任务  定时任务
     */
    @Override
    @Scheduled(fixedDelay = 10000)
    public void doTask() {
        LambdaQueryWrapper<SysThirdExceptionRequest> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysThirdExceptionRequest::getStatus, ThirdApiStatusEnum.fail.getValue());
        wrapper.orderByAsc(SysThirdExceptionRequest::getCreateTime);
        wrapper.last("limit 1");
        List<SysThirdExceptionRequest> thirdExceptionRequestList = list(wrapper);
        // log.info("定时任务当前执行数量 = {}", thirdExceptionRequestList.size());
        for (SysThirdExceptionRequest request : thirdExceptionRequestList) {
            try {
                Date planTime = request.getPlanTime();
                if (planTime == null) {
                    executeException(request.getCode());
                } else {
                    boolean after = planTime.before(DateUtils.getNowDate());
                    if (after) {
                        executeException(request.getCode());
                    }
                }
            } catch (Exception e) {
                log.error("doTask = {}", e);
            }
        }
    }

}
