package com.clx.performance.service.impl.linewarn;

import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.clx.message.feign.ClxMessageOpenapiFeign;
import com.clx.message.req.message.AliSmsMessageReq;
import com.clx.message.req.message.ClinkMessageReq;
import com.clx.order.feign.OrderFeign;
import com.clx.order.vo.feign.FeignOrderInfoVO;
import com.clx.performance.config.ClxMessageConfig;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dao.linewarn.LineWarnInfoDao;
import com.clx.performance.dao.linewarn.LineWarnOrderGoodsDao;
import com.clx.performance.dao.vehiclewarn.VehicleWarnUserDao;
import com.clx.performance.dto.linewarn.LineWarnCommonInfoDTO;
import com.clx.performance.enums.OrderGoodsStatusEnum;
import com.clx.performance.enums.ResultEnum;
import com.clx.performance.enums.linewarn.LineWarnOrderGoodsEnum;
import com.clx.performance.extranal.user.OrderService;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.linewarn.LineWarnInfo;
import com.clx.performance.model.linewarn.LineWarnOrderGoods;
import com.clx.performance.model.vehiclewarn.VehicleWarnUser;
import com.clx.performance.param.mq.linewarn.LineWarnLineWarnMqParam;
import com.clx.performance.param.mq.linewarn.LineWarnNoticeMqParam;
import com.clx.performance.param.mq.linewarn.LineWarnOrderChildWarnMqParam;
import com.clx.performance.param.mq.linewarn.LineWarnOrderGoodsAddMqParam;
import com.clx.performance.service.linewarn.*;
import com.clx.performance.utils.LocalDateTimeUtils;
import com.clx.performance.utils.gd.GdUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class LineWarnMqHandlerServiceImpl implements LineWarnMqHandlerService {

    // 缺省装卸车时间
    private static final int DEFAULT_LOAD_UNLOAD_TIME = 60;
    private static final int DEFAULT_LOAD_UNLOAD_DAY = 7;

    @Autowired
    private ClxMessageConfig clxMessageConfig;
    @Autowired
    private OrderGoodsDao orderGoodsDao;
    @Autowired
    private LineWarnOrderGoodsDao lineWarnOrderGoodsDao;
    @Autowired
    private OrderFeign orderFeign;
    @Autowired
    private OrderService orderService;
    @Autowired
    private GdUtils gdUtils;
    @Autowired
    private LineWarnTakeWarnService lineWarnTakeWarnService;
    @Autowired
    private LineWarnUnloadWarnService lineWarnUnloadWarnService;
    @Autowired
    private LineWarnLoadWarnService lineWarnLoadWarnService;
    @Autowired
    private LineWarnCongestionWarnService lineWarnCongestionWarnService;
    @Autowired
    private LineWarnWeatherWarnService lineWarnWeatherWarnService;
    @Autowired
    private LineWarnOrderChildWarnService lineWarnOrderChildWarnService;
    @Autowired
    private LineWarnLineWarnService lineWarnLineWarnService;
    @Autowired
    private OrderChildDao orderChildDao;
    @Autowired
    private LineWarnInfoDao lineWarnInfoDao;
    @Autowired
    private VehicleWarnUserDao vehicleWarnUserDao;
    @Autowired
    private ClxMessageOpenapiFeign clxMessageOpenapiFeign;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void orderGoodsAdd(LineWarnOrderGoodsAddMqParam mq) {
        OrderGoods orderGoods = orderGoodsDao
                .getByOrderGoodsNo(mq.getOrderGoodsNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);

        FeignOrderInfoVO orderInfo = orderService
                .getOrderInfo(orderGoods.getOrderNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);

        // 计算货源地到
        int arriveSendExpectTime = gdUtils.getNeedTime(new BigDecimal[]{orderGoods.getSendLongitude(),
                orderGoods.getSendLatitude()}, orderGoods.getReceiveLongitude(), orderGoods.getReceiveLatitude());

        LineWarnOrderGoods lineWarnOrderGoods = new LineWarnOrderGoods();
        lineWarnOrderGoods.setOrderGoodsNo(orderGoods.getOrderGoodsNo());
        lineWarnOrderGoods.setTransportEndTime(LocalDateTimeUtils.parseTime(orderInfo.getTransportEndTime()));
        lineWarnOrderGoods.setPendingOrderTime(orderGoods.getPendingOrderTime());
        lineWarnOrderGoods.setArriveReceiveExpectTime(arriveSendExpectTime==0? null : arriveSendExpectTime);
        lineWarnOrderGoodsDao.saveEntity(lineWarnOrderGoods);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void lineWarn(LineWarnLineWarnMqParam mq) {
        LineWarnOrderGoods lineWarnOrderGoods = lineWarnOrderGoodsDao
                .getByOrderGoodsNo(mq.getOrderGoodsNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);
        OrderGoods orderGoods = orderGoodsDao
                .getByOrderGoodsNo(mq.getOrderGoodsNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);

        LineWarnCommonInfoDTO lineWarnCommonInfo = new LineWarnCommonInfoDTO();
        lineWarnCommonInfo.setOrderGoodsNo(orderGoods.getOrderGoodsNo());
        lineWarnCommonInfo.setTransportEndTime(lineWarnOrderGoods.getTransportEndTime());
        lineWarnCommonInfo.setPendingOrderTime(lineWarnOrderGoods.getPendingOrderTime());
        lineWarnCommonInfo.setArriveReceiveExpectTime(lineWarnOrderGoods.getArriveReceiveExpectTime());

        // 任务量
        lineWarnCommonInfo.setTaskWeight(orderGoods.getExtractWeight());
        // 装卸车时间
        Integer loadTimeAvg = orderChildDao
                .loadTimeAvg(orderGoods.getSendAddressId(), orderGoods.getReceiveAddressId(),
                orderGoods.getSendSystemAddressId(), orderGoods.getReceiveSystemAddressId(),
                LocalDateTimeUtils.formatTime(LocalDateTime.now().minusDays(DEFAULT_LOAD_UNLOAD_DAY)));
        Integer unloadTimeAvg = orderChildDao
                .unloadTimeAvg(orderGoods.getSendAddressId(), orderGoods.getReceiveAddressId(),
                orderGoods.getSendSystemAddressId(), orderGoods.getReceiveSystemAddressId(),
                LocalDateTimeUtils.formatTime(LocalDateTime.now().minusDays(DEFAULT_LOAD_UNLOAD_DAY)));
        lineWarnCommonInfo.setLoadTimeAvg(loadTimeAvg!=null? loadTimeAvg:DEFAULT_LOAD_UNLOAD_TIME);
        lineWarnCommonInfo.setUnloadTimeAvg(unloadTimeAvg!=null? unloadTimeAvg:DEFAULT_LOAD_UNLOAD_TIME);

        log.info("线路预警, lineWarnCommonInfo:{}", lineWarnCommonInfo);

        // 接单预警
        try {
            lineWarnTakeWarnService.takeWarn(orderGoods, lineWarnCommonInfo);
        }catch (Exception e){
            log.info("接单预警异常，msg:{}", e.getMessage());
        }

        // 装车预警
        try{
            lineWarnLoadWarnService.loadWarn(orderGoods, lineWarnCommonInfo);
        }catch (Exception e){
            log.info("装车预警异常，msg:{}", e.getMessage());
        }

        // 卸车预警
        try{
            lineWarnUnloadWarnService.unloadWarn(orderGoods, lineWarnCommonInfo);
        }catch (Exception e){
            log.info("卸车预警异常，msg:{}", e.getMessage());
        }

        // 天气预警
        try{
            lineWarnWeatherWarnService.weatherWarn(orderGoods, lineWarnCommonInfo);
        }catch (Exception e){
            log.info("天气预警异常，msg:{}", e.getMessage());
        }



        // 拥堵预警
        try {
            lineWarnCongestionWarnService.congestionWarn(orderGoods, lineWarnCommonInfo);
        } catch (Exception e) {
            log.info("拥堵预警异常，msg:{}", e.getMessage());
        }

        // 线路异常
        try {
            lineWarnLineWarnService.lineAbnormalWarn(orderGoods, lineWarnCommonInfo);
        } catch (Exception e) {
            log.info("线路异常，msg:{}", e.getMessage());
        }

        if (Objects.equals(orderGoods.getOrderGoodsStatus(), OrderGoodsStatusEnum.Status.CANCEL.getCode())
                || Objects.equals(orderGoods.getOrderGoodsStatus(), OrderGoodsStatusEnum.Status.SUCCESS.getCode())
                || Objects.equals(orderGoods.getOrderGoodsStatus(), OrderGoodsStatusEnum.Status.COMPLETED.getCode())
        ){
            lineWarnOrderGoods.setWarnStatus(LineWarnOrderGoodsEnum.WarnStatus.DISABLE.getCode());
            lineWarnOrderGoodsDao.updateWarnStatus(lineWarnOrderGoods);
        }

    }

    @Override
    public void notice(LineWarnNoticeMqParam mq) {
        LineWarnInfo vehicleWarnInfo = lineWarnInfoDao
                .findById(mq.getInfoId()).orElseThrow(ResultEnum.DATA_NOT_FIND);

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

        // 过滤需要通知的人员
        List<VehicleWarnUser> list = vehicleWarnUserDao.listAllEnable();
        for (VehicleWarnUser item : list) {
            List<Integer> warnTypeList = JSON.parseArray(item.getLineWarnTypeJson(),Integer.class);
            if (warnTypeList.contains(vehicleWarnInfo.getWarnType())){
                mobileList.add(item.getMobile());
            }
        }

        if (mobileList.isEmpty()) {return;}
        log.info("线路预警通知, id:{}, mobileList:{}", vehicleWarnInfo.getId(), JSON.toJSONString(mobileList));

        if (vehicleWarnInfo.getWarnLevel() == 2){   //2级短信
            sendSms(mobileList, vehicleWarnInfo.getWarnName()
                    , vehicleWarnInfo.getOrderGoodsNo());
        }
        else if (vehicleWarnInfo.getWarnLevel() == 3) {   //3级外呼+短信
            sendSms(mobileList, vehicleWarnInfo.getWarnName()
                    , vehicleWarnInfo.getOrderGoodsNo());
            sendClink(mobileList, vehicleWarnInfo.getWarnName()
                    , vehicleWarnInfo.getOrderGoodsNo());
        }

    }

    /**
     * 发送预警短信
     */
    @Override
    public void sendSms(List<String> mobileList, String warnName, String orderGoodsNo) {
        //触发${warnName}预警；货单${orderGoodsNo}；请尽快核实情况。

        AliSmsMessageReq req = new AliSmsMessageReq();
        req.setTemplateCode(clxMessageConfig.getLineWarnTemplateCode());
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("warnName", warnName);
        jsonObject.set("orderGoodsNo", orderGoodsNo);
        req.setChannelId(clxMessageConfig.getChannelId());
        req.setAppId(clxMessageConfig.getAppId().toString());
        req.setContent(jsonObject.toString());
        req.setExpire(300L);

        for (String mobile : mobileList) {
            req.setMobile(mobile);
            clxMessageOpenapiFeign.sendAliSms(req);
        }

    }

    /**
     * 发送预警外呼
     */
    @Override
    public void sendClink(List<String> mobileList, String warnName, String orderGoodsNo) {
        //触发${warnName}预警；货单${orderGoodsNo}；请尽快核实情况。
        ClinkMessageReq req = new ClinkMessageReq();

        StringBuilder sb = new StringBuilder();
        sb.append("触发");
        sb.append(warnName);
        sb.append("预警；货单");
        sb.append(orderGoodsNo);
        sb.append("；请尽快核实情况");

        String content = sb.toString();

        req.setChannelId(clxMessageConfig.getVehicleWarnChannelId());
        req.setAppId(clxMessageConfig.getAppId().toString());
        req.setContent(content);

        for (String mobile : mobileList) {
            req.setMobile(mobile);
            clxMessageOpenapiFeign.sendClink(req);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void orderChildWarn(LineWarnOrderChildWarnMqParam mq) {
        LineWarnOrderGoods lineWarnOrderGoods = lineWarnOrderGoodsDao
                .getByOrderGoodsNo(mq.getOrderGoodsNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);
        OrderGoods orderGoods = orderGoodsDao
                .getByOrderGoodsNo(mq.getOrderGoodsNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);
        if (Objects.equals(lineWarnOrderGoods.getWarnStatus(), LineWarnOrderGoodsEnum.WarnStatus.DISABLE.getCode())) {
            return;
        }

        // 运单异常
        try{
            lineWarnOrderChildWarnService.orderChildWarn(orderGoods);
        }catch (Exception e){
            log.info("运单异常异常，msg:{}", e.getMessage());
        }
    }

}
