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

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.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.vehiclewarn.VehicleWarnChildDao;
import com.clx.performance.dao.vehiclewarn.VehicleWarnInfoDao;
import com.clx.performance.dao.vehiclewarn.VehicleWarnUserDao;
import com.clx.performance.dto.vehiclewarn.VehicleWarnCommonInfoDTO;
import com.clx.performance.enums.OrderChildEnum;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.ResultEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnChildEnum;
import com.clx.performance.extranal.user.OrderService;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.vehiclewarn.VehicleWarnChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnInfo;
import com.clx.performance.model.vehiclewarn.VehicleWarnUser;
import com.clx.performance.param.mq.trace.TruckTraceSyncMqParam;
import com.clx.performance.param.mq.vehiclewarn.VehicleWarnChildAddMqParam;
import com.clx.performance.param.mq.vehiclewarn.VehicleWarnTruckWarnMqParam;
import com.clx.performance.param.mq.vehiclewarn.VehicleWarnTruckWarnNoticeMqParam;
import com.clx.performance.service.linewarn.LineWarnMqService;
import com.clx.performance.service.trace.TruckTraceMqHandlerService;
import com.clx.performance.service.vehiclewarn.*;
import com.clx.performance.utils.LocalDateTimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Slf4j
@Service
public class VehicleWarnMqHandlerServiceImpl implements VehicleWarnMqHandlerService {
    // 前往目的地距离
    private static final Integer DISTANCE_DEFAULT = 2000;
    // 车辆轨迹同步时间
    private static final int TRUCK_TRACE_SYNC_TIME = 5;

    @Autowired
    private OrderChildDao orderChildDao;
    @Autowired
    private VehicleWarnChildDao vehicleWarnChildDao;
    @Autowired
    private VehicleWarnInfoDao vehicleWarnInfoDao;
    @Autowired
    private OrderGoodsDao orderGoodsDao;
    @Autowired
    private VehicleWarnUserDao vehicleWarnUserDao;
    @Autowired
    private VehicleWarnSendAddressWarnService vehicleWarnSendAddressWarnService;
    @Autowired
    private VehicleWarnLoadAndUnloadWarnService vehicleWarnLoadAndUnloadWarnService;
    @Autowired
    private VehicleWarnReceiveAddressWarnService vehicleWarnReceiveAddressWarnService;
    @Autowired
    private VehicleWarnCommonService vehicleWarnCommonService;
    @Autowired
    private ClxMessageConfig clxMessageConfig;
    @Autowired
    private ClxMessageOpenapiFeign clxMessageOpenapiFeign;
    @Autowired
    private VehicleWarnParkWarnService vehicleWarnParkWarnService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private VehicleWarnDelayWarnService vehicleWarnDelayWarnService;
    @Autowired
    private TruckTraceMqHandlerService truckTraceMqHandlerService;
    @Autowired
    private LineWarnMqService lineWarnMqService;

    @Override
    public void orderChildAdd(VehicleWarnChildAddMqParam mq) {
        OrderChild orderChild = orderChildDao.getByChildNo(mq.getChildNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);
        OrderGoods orderGoods = orderGoodsDao
                .getByOrderGoodsNo(orderChild.getOrderGoodsNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);

        // 同步车辆轨迹
        TruckTraceSyncMqParam truckTraceSyncMqParam = new TruckTraceSyncMqParam();
        truckTraceSyncMqParam.setChildNo(orderChild.getChildNo());
        truckTraceSyncMqParam.setTruckNo(orderChild.getTruckNo());
        truckTraceSyncMqParam.setBeginTime(
                LocalDateTimeUtils.formatTime(LocalDateTime.now().minusMinutes(TRUCK_TRACE_SYNC_TIME)));
        truckTraceSyncMqParam.setEndTime(LocalDateTimeUtils.formatTime());
        try {
            truckTraceMqHandlerService.truckTracSync(truckTraceSyncMqParam);
        }catch (Exception e){
            log.info("同步车辆轨迹失败, msg:{}", e.getMessage());
        }

        // 计算预计时间
        BigDecimal[] currentPosition = vehicleWarnCommonService.getCurrentPosition(orderChild.getTruckNo(),
                orderChild.getDriverUserNo());
        int arriveSendExpectTime = vehicleWarnCommonService.getNeedTime(currentPosition,
                orderGoods.getSendLongitude(), orderGoods.getSendLatitude());
        int arriveReceiveExpectTime = vehicleWarnCommonService
                .getNeedTime(new BigDecimal[]{orderGoods.getSendLongitude(),
                orderGoods.getSendLatitude()}, orderGoods.getReceiveLongitude(), orderGoods.getReceiveLatitude());

        int needDistance = vehicleWarnCommonService.getNeedDistance(new BigDecimal[]{orderGoods.getSendLongitude(),
                orderGoods.getSendLatitude()}, orderGoods.getReceiveLongitude(), orderGoods.getReceiveLatitude());

        VehicleWarnChild vehicleWarnChild = new VehicleWarnChild();
        vehicleWarnChild.setOrderGoodsNo(orderChild.getOrderGoodsNo());
        vehicleWarnChild.setChildNo(orderChild.getChildNo());
        vehicleWarnChild.setTruckNo(orderChild.getTruckNo());
        vehicleWarnChild.setDriverUserNo(orderChild.getDriverUserNo());
        vehicleWarnChild.setSendLongitude(orderGoods.getSendLongitude());
        vehicleWarnChild.setSendLatitude(orderGoods.getSendLatitude());
        vehicleWarnChild.setReceiveLongitude(orderGoods.getReceiveLongitude());
        vehicleWarnChild.setReceiveLatitude(orderGoods.getReceiveLatitude());
        vehicleWarnChild.setArriveSendExpectTime(arriveSendExpectTime==0? null : arriveSendExpectTime);
        vehicleWarnChild.setArriveReceiveExpectTime(arriveReceiveExpectTime==0? null : arriveReceiveExpectTime);
        vehicleWarnChild.setReceiveAddressDistance(needDistance);

        vehicleWarnChild.setTakeTime(orderChild.getPayTime());
        vehicleWarnChild.setTraceTime(LocalDateTime.now());
        vehicleWarnChild.setWarnStatus(VehicleWarnChildEnum.WarnStatus.ENABLE.getCode());

        vehicleWarnChildDao.saveEntity(vehicleWarnChild);
    }

    @Override
    public void truckWarn(VehicleWarnTruckWarnMqParam mq) {
        OrderChild orderChild = orderChildDao.getByChildNo(mq.getChildNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);
        OrderGoods orderGoods = orderGoodsDao
                .getByOrderGoodsNo(orderChild.getOrderGoodsNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);

        VehicleWarnChild vehicleWarnChild = vehicleWarnChildDao
                .findByChildNo(mq.getChildNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);

        VehicleWarnCommonInfoDTO commonInfo = new VehicleWarnCommonInfoDTO();
        commonInfo.setChildNo(orderChild.getChildNo());
        commonInfo.setLastArriveSendTime(orderGoods.getLastArriveSendTime());
        commonInfo.setLastArriveReceiveTime(orderGoods.getLastArriveReceiveTime());
        commonInfo.setCurrentTime(LocalDateTime.now());

        FeignOrderInfoVO orderInfo = orderService
                .getOrderInfo(orderGoods.getOrderNo()).orElseThrow(PerformanceResultEnum.ORDER_INVALID);
        commonInfo.setTransportEndTime(LocalDateTimeUtils.parseTime(orderInfo.getTransportEndTime()));

        // 获取当前位置
        commonInfo.setCurrentPosition(vehicleWarnCommonService
                .getCurrentPosition(orderChild.getTruckNo(), orderChild.getDriverUserNo()));

        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.CREATED.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.PAY.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_SEND.getCode())
        ) {
            // 距货源地时间
            commonInfo.setSendAddressTime(vehicleWarnCommonService
                    .getNeedTime(commonInfo.getCurrentPosition(), vehicleWarnChild.getSendLongitude()
                            , vehicleWarnChild.getSendLatitude()));
        }

        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARRIVE_SEND.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.LOAD.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_RECEIVE.getCode())
        ) {
            // 距目的地时间
            commonInfo.setReceiveAddressTime(vehicleWarnCommonService
                    .getNeedTime(commonInfo.getCurrentPosition()
                            , vehicleWarnChild.getReceiveLongitude(), vehicleWarnChild.getReceiveLatitude()));
            // 距目的地距离
            commonInfo.setReceiveAddressDistance(vehicleWarnCommonService
                    .getNeedDistance(commonInfo.getCurrentPosition()
                            , vehicleWarnChild.getReceiveLongitude(), vehicleWarnChild.getReceiveLatitude()));
        }

        // 未装车前往目的地判断
        commonInfo.setGotoReceive(false);
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARRIVE_SEND.getCode())){

            // 首次不处理预警
            if (vehicleWarnChild.getEstimateLoadTime() != null){
                commonInfo.setGotoReceive(true);
                commonInfo.setGotoReceiveTime(vehicleWarnChild.getEstimateLoadTime());
            }
            else {
                Integer needDistance = commonInfo.getReceiveAddressDistance();
                if (vehicleWarnChild.getReceiveAddressDistance()-needDistance > DISTANCE_DEFAULT){
                    commonInfo.setGotoReceive(true);
                    commonInfo.setGotoReceiveTime(LocalDateTime.now());

                    vehicleWarnChild.setEstimateLoadTime(commonInfo.getGotoReceiveTime());
                    vehicleWarnChildDao.updateEstimateLoadTime(vehicleWarnChild);
                }
            }
        }
        else {
            if (orderChild.getLoadTime() != null){
                commonInfo.setGotoReceive(true);
                commonInfo.setGotoReceiveTime(orderChild.getLoadTime());
            }
        }

        log.info("commonInfo:{}", commonInfo);


        // 前往货源地超时
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.CREATED.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.PAY.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_SEND.getCode())
        ){
            try {
                vehicleWarnSendAddressWarnService.gotoSendAddressTimeout(orderChild, vehicleWarnChild, commonInfo);
            }catch (Exception e){
                log.error("前往货源地超时错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        // 到达货源地超时
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.CREATED.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.PAY.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_SEND.getCode())
        ){
            try{
                vehicleWarnSendAddressWarnService.arriveSendAddressTimeout(orderChild, vehicleWarnChild, commonInfo);
            }catch (Exception e){
                log.error("到达货源地超时错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        // 装车超时
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARRIVE_SEND.getCode())
        ){
            try{
                vehicleWarnLoadAndUnloadWarnService.loadTimeout(orderChild, vehicleWarnChild);
            }catch (Exception e){
                log.error("装车超时错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        // 卸车超时
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARRIVE_RECEIVE.getCode())
        ){
            try{
                vehicleWarnLoadAndUnloadWarnService.unloadTimeout(orderChild, vehicleWarnChild);
            }catch (Exception e){
                log.error("卸车超时错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        // 前往目的地超时
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARRIVE_SEND.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.LOAD.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_RECEIVE.getCode())
        ){
            try {
                vehicleWarnReceiveAddressWarnService
                        .gotoReceiveAddressTimeout(orderChild, vehicleWarnChild, commonInfo);
            }catch (Exception e){
                log.info("前往目的地超时错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        // 到达目的地超时
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARRIVE_SEND.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.LOAD.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_RECEIVE.getCode())
        ){
            try {
                vehicleWarnReceiveAddressWarnService
                        .arriveReceiveAddressTimeout(orderChild, vehicleWarnChild, commonInfo);
            }catch (Exception e){
                log.info("到达目的地超时错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        // 停留超时
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARRIVE_SEND.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.LOAD.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_RECEIVE.getCode())
        ){
            try {
                vehicleWarnParkWarnService.packTimeout(orderChild, vehicleWarnChild, commonInfo);
            }catch (Exception e){
                log.info("停留超时错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        // 敏感区停留超时
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARRIVE_SEND.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.LOAD.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_RECEIVE.getCode())
        ){
            try {
                vehicleWarnParkWarnService.sensitiveAreaParkTimeout(orderChild, vehicleWarnChild, commonInfo);
            }catch (Exception e){
                log.info("敏感区停留超时错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        // 运单延误
        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.CREATED.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.PAY.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.GO_TO_SEND.getCode())
        ){
            try {
                vehicleWarnDelayWarnService.delayTimeout(orderChild, vehicleWarnChild, commonInfo);
            }catch (Exception e){
                log.info("运单延误错误, msg:{}", ExceptionUtils.getStackTrace(e));
            }
        }

        if (Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.COMPLETE.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.DRIVER_CANCEL.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.PLATFORM_CANCEL.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.OWNER_CANCEL.getCode())
                || Objects.equals(orderChild.getStatus(), OrderChildEnum.Status.ARTIFICIAL_CANCEL.getCode())
        ) {
            // 运单结束不再预警
            vehicleWarnChild.setWarnStatus(VehicleWarnChildEnum.TraceStatus.DISABLE.getCode());
            vehicleWarnChildDao.updateWarnStatus(vehicleWarnChild);
        }

    }

    @Override
    public void truckWarnNotice(VehicleWarnTruckWarnNoticeMqParam mq) {
        VehicleWarnInfo vehicleWarnInfo = vehicleWarnInfoDao
                .findById(mq.getInfoId()).orElseThrow(ResultEnum.DATA_NOT_FIND);

        // 发送mq（运单异常）
        lineWarnMqService.orderChildWarn(vehicleWarnInfo.getOrderGoodsNo(), vehicleWarnInfo.getChildNo());

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

        // 过滤需要通知的人员
        List<VehicleWarnUser> list = vehicleWarnUserDao.listAllEnable();
        for (VehicleWarnUser item : list) {
            List<Integer> warnTypeList = JSON.parseArray(item.getWarnTypeJson(),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.getTruckNo(), vehicleWarnInfo.getChildNo());
        }
        else if (vehicleWarnInfo.getWarnLevel() == 3) {   //3级外呼+短信
            sendSms(mobileList, vehicleWarnInfo.getWarnName()
                    , vehicleWarnInfo.getTruckNo(), vehicleWarnInfo.getChildNo());
            sendClink(mobileList, vehicleWarnInfo.getWarnName()
                    , vehicleWarnInfo.getTruckNo(), vehicleWarnInfo.getChildNo());
        }

    }

    /**
     * 发送预警短信
     */
    @Override
    public void sendSms(List<String> mobileList, String warnName, String truckNo, String childNo) {
        //触发${warnName}预警；车牌号${truckNo}；运单${childNo}；请尽快核实情况

        AliSmsMessageReq req = new AliSmsMessageReq();
        req.setTemplateCode(clxMessageConfig.getVehicleWarnTemplateCode());
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("warnName", warnName);
        jsonObject.set("truckNo", truckNo);
        jsonObject.set("childNo", childNo);
        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 truckNo, String childNo) {
        //触发{指定预警名称}预警；车牌号{车牌号}；运单{运单号}；请尽快核实情况
        ClinkMessageReq req = new ClinkMessageReq();

        StringBuilder sb = new StringBuilder();
        sb.append("触发");
        sb.append(warnName);
        sb.append("预警；车牌号");
        sb.append(truckNo);
        sb.append("；运单");
        sb.append(childNo);
        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);
        }

    }

}
