package com.prolog.rdc.tms.service.fleetManagement.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.prolog.common.util.ToolKits;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.rdc.tms.constant.BussinessConstant;
import com.prolog.rdc.tms.constant.DataDictionaryConstant;
import com.prolog.rdc.tms.dao.mapper.TmsVehicleGPSHistoryMapper;
import com.prolog.rdc.tms.dao.mapper.TmsVehicleGPSMapper;
import com.prolog.rdc.tms.model.dto.ShipAndLoadingBillDTO;
import com.prolog.rdc.tms.model.dto.ShipbillAndLoadingbillInfoDTO;
import com.prolog.rdc.tms.model.dto.fleetManagement.VehicleGpsDTO;
import com.prolog.rdc.tms.model.entity.SysParamConfigModel;
import com.prolog.rdc.tms.model.entity.line.TmsVehicleGPSHistoryModel;
import com.prolog.rdc.tms.model.entity.line.TmsVehicleGPSModel;
import com.prolog.rdc.tms.model.vo.fleetManagement.VehicleGpsQueryVO;
import com.prolog.rdc.tms.model.vo.fleetManagement.VehicleGpsSaveVO;
import com.prolog.rdc.tms.rmi.feign.BusinessComingRecordFeign;
import com.prolog.rdc.tms.service.basicConfigure.SysParamConfigService;
import com.prolog.rdc.tms.service.fleetManagement.VehicleGpsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 *
 *
 * 车辆GPS数据管理实现层
 *
 * @className :VehicleGpsServiceImpl
 * @author :xyf
 * @creationTime :2021/09/01
 *
 * @version :1.0.0
 *
 */
@Slf4j
@Service
public class VehicleGpsServiceImpl implements VehicleGpsService {

    @Autowired
    private SysParamConfigService sysParamConfigService;

    @Autowired
    private TmsVehicleGPSMapper tmsVehicleGPSMapper;

    @Autowired
    private BusinessComingRecordFeign businessComingRecordFeign;

    @Autowired
    private TmsVehicleGPSHistoryMapper tmsVehicleGPSHistoryMapper;

    /**
     * 写入GPS定位数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveVehicleGps(VehicleGpsSaveVO vo) throws Exception {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前人员没有操作权限");

        //获取定位间隔参数
        SysParamConfigModel sysParamConfig=sysParamConfigService.getValue(BussinessConstant.LOCATE_INTERVAL);
        if(ToolKits.isEmpty(sysParamConfig)){
            throw new PrologException("定位间隔参数查询失败");
        }
        String value=sysParamConfig.getValue();

        //String id = sysCodeengineService.getCodeNumberByCode(SeriaNnumberConstant.TMS_VEHICLE_GPS_ID, "L");
        //ToolKits.isParamNull(id, "ID生成失败");

        TmsVehicleGPSModel model=new TmsVehicleGPSModel();
        //数据量大 用取号器容易主键冲突 所以用随机数long型生成主键
        BeanUtils.copyProperties(vo,model);
        model.setId(new Random().nextLong());
        model.setDriverId(user.getUserid());
        model.setEnterpriseId(user.getEnterpriseId());
        model.setEnterpriseName(user.getEnterpriseName());
        model.setCreatetime(DateUtil.date());
        model.setCreateperson(user.getNickname());
        model.setUpdatetime(DateUtil.date());
        model.setUpdateperson(user.getNickname());

        if(ToolKits.isNotEmpty(vo.getFlag())){//启运登记、送达确认发起定位写入,直接保存数据
            RestMessage<ShipbillAndLoadingbillInfoDTO> msg = businessComingRecordFeign.getInfoByDriverId(model.getShipbillId());
            if (!msg.isSuccess()) {
                throw new PrologException("装车单信息查询接口调用失败：" + msg.getMessage());
            }
            ShipbillAndLoadingbillInfoDTO shipbillAndLoadingbillInfo=msg.getData();
            model.setLoadingbillId(shipbillAndLoadingbillInfo.getLoadingbillId());
            model.setLoadingbillNo(shipbillAndLoadingbillInfo.getLoadingbillNo());
            model.setVehicleId(shipbillAndLoadingbillInfo.getVehicleId());
            model.setVehicleCode(shipbillAndLoadingbillInfo.getVehicleCode());
            model.setVehiclePlateNumber(shipbillAndLoadingbillInfo.getVehiclePlateNumber());
            model.setDriverCode(shipbillAndLoadingbillInfo.getDriverCode());
            model.setDriverName(shipbillAndLoadingbillInfo.getDriverName());
            model.setDriverPhoneNumber(shipbillAndLoadingbillInfo.getDriverPhoneNumber());
            tmsVehicleGPSMapper.save(model);
        }else{//司机登录小程序后 定时发起的定位写入
            Calendar beforeTime = Calendar.getInstance();
            beforeTime.add(Calendar.MINUTE, -(Integer.parseInt(value)));
            Date oldTime = beforeTime.getTime();

            //判断当前司机是否存在已启运登记 按写入时间倒序排
            Criteria criteriaR = Criteria.forClass(TmsVehicleGPSModel.class);
            Restriction rr1 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            Restriction rr2 = Restrictions.eq("driverId", user.getUserid());
            Restriction rr3 = Restrictions.isNotNull(TmsVehicleGPSModel::getStartShipTime);
            criteriaR.setRestriction(Restrictions.and(rr1,rr2,rr3));
            criteriaR.setOrder(Order.newInstance().desc(new String[] { "createtime" }));
            List<TmsVehicleGPSModel> tmsVehicleGPSModelList = tmsVehicleGPSMapper.findByCriteria(criteriaR);

            if(ToolKits.isNotEmpty(tmsVehicleGPSModelList)&&tmsVehicleGPSModelList.size()>0){
                RestMessage<ShipbillAndLoadingbillInfoDTO> msg = businessComingRecordFeign.getInfoByDriverId(tmsVehicleGPSModelList.get(0).getShipbillId());
                if (!msg.isSuccess()) {
                    throw new PrologException("装车单信息查询接口调用失败：" + msg.getMessage());
                }

                ShipbillAndLoadingbillInfoDTO shipbillAndLoadingbillInfo=msg.getData();
                if(ObjectUtil.notEqual(shipbillAndLoadingbillInfo.getStatus(),DataDictionaryConstant.SHIPBILL_STATUS_HD_ZB)&&
                        ObjectUtil.notEqual(shipbillAndLoadingbillInfo.getStatus(), DataDictionaryConstant.SHIPBILL_STATUS_HD_PIC)&&
                        ObjectUtil.notEqual(shipbillAndLoadingbillInfo.getStatus(),DataDictionaryConstant.SHIPBILL_STATUS_END)){
                    //已启运,还未送达
                    model.setLoadingbillId(shipbillAndLoadingbillInfo.getLoadingbillId());
                    model.setLoadingbillNo(shipbillAndLoadingbillInfo.getLoadingbillNo());
                    model.setShipbillId(tmsVehicleGPSModelList.get(0).getShipbillId());
                    model.setShipbillNo(tmsVehicleGPSModelList.get(0).getShipbillNo());
                    model.setVehicleId(shipbillAndLoadingbillInfo.getVehicleId());
                    model.setVehicleCode(shipbillAndLoadingbillInfo.getVehicleCode());
                    model.setVehiclePlateNumber(shipbillAndLoadingbillInfo.getVehiclePlateNumber());
                    model.setDriverCode(shipbillAndLoadingbillInfo.getDriverCode());
                    model.setDriverName(shipbillAndLoadingbillInfo.getDriverName());
                    model.setDriverPhoneNumber(shipbillAndLoadingbillInfo.getDriverPhoneNumber());
                }
            }

            //获取当前司机最后一次写入GPS数据的时间
            Criteria criteria = Criteria.forClass(TmsVehicleGPSModel.class);
            Restriction r1 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            Restriction r2 = Restrictions.eq("driverId", user.getUserid());
            criteria.setRestriction(Restrictions.and(r1,r2));
            criteria.setOrder(Order.newInstance().desc(new String[] { "createtime" }));
            List<TmsVehicleGPSModel> tmsVehicleGPSModels = tmsVehicleGPSMapper.findByCriteria(criteria);

            if(ToolKits.isNotEmpty(tmsVehicleGPSModels)&&tmsVehicleGPSModels.size()>0){
                Date lastTime=tmsVehicleGPSModels.get(0).getCreatetime();
                //计算当前时间和该司机最后一次定位的时间之间的间隔 是否大于等于定位间隔参数
                Date begin = lastTime;
                Date end = new Date();
                long between = (end.getTime() - begin.getTime())/1000;
                long min = between/60;

                if(min>=Integer.parseInt(value)){
                    tmsVehicleGPSMapper.save(model);
                }
            }else{
                tmsVehicleGPSMapper.save(model);
            }
        }
    }

    /**
     * GPS定位数据查询
     */
    @Override
    public List<VehicleGpsDTO> queryVehicleGps(VehicleGpsQueryVO vo) throws Exception {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前人员没有操作权限");

        Criteria criteriaS = Criteria.forClass(TmsVehicleGPSModel.class);
        Restriction rs1 = Restrictions.eq(TmsVehicleGPSModel::getShipbillId, vo.getShipbillId());
        Restriction rs2 = Restrictions.isNotNull(TmsVehicleGPSModel::getStartShipTime);
        Restriction rs3 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteriaS.setRestriction(Restrictions.and(rs1,rs2,rs3));
        List<TmsVehicleGPSModel> list = tmsVehicleGPSMapper.findByCriteria(criteriaS);
        if(ToolKits.isNotEmpty(list)&&list.size()>0) {
            Date startDate=list.get(0).getStartShipTime();
            Date endDate=null;

            rs2 = Restrictions.isNotNull(TmsVehicleGPSModel::getDeliveryTime);
            criteriaS.setRestriction(Restrictions.and(rs1,rs2,rs3));
            list = tmsVehicleGPSMapper.findByCriteria(criteriaS);

            Boolean b=false;
            if(ToolKits.isNotEmpty(list)&&list.size()>0) {//已送达确认
                b=true;
                endDate=list.get(0).getDeliveryTime();
            }

            Criteria criteria = Criteria.forClass(TmsVehicleGPSModel.class);
            Restriction r1 = Restrictions.eq("shipbillId", vo.getShipbillId());
            Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            Restriction r3 = Restrictions.ge("createtime", startDate);
            Restriction r4 = ToolKits.isEmpty(vo.getEndDate()) ? null : Restrictions.le("createtime", endDate);
            criteria.setRestriction(Restrictions.and(r1, r2, r3, r4));
            criteria.setOrder(Order.newInstance().asc(new String[]{"createtime"}));
            List<TmsVehicleGPSModel> dataList = tmsVehicleGPSMapper.findByCriteria(criteria);
            List<VehicleGpsDTO> dtos = Lists.newArrayList();

            for (TmsVehicleGPSModel model : dataList) {
                VehicleGpsDTO dto = new VehicleGpsDTO();
                BeanUtils.copyProperties(model, dto);
                if(b){
                    dto.setIsDelivery("1");
                }else{
                    dto.setIsDelivery("0");
                }
                dtos.add(dto);
            }
            return dtos;
        }else{
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveVehicleGpsNew(VehicleGpsSaveVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前人员没有操作权限");
        log.info("saveVehicleGpsNew,vo={}", JSON.toJSONString(vo));
        //启运登记、送达确认发起定位写入,直接保存数据
        if (ToolKits.isNotEmpty(vo.getFlag())) {
            List<ShipAndLoadingBillDTO> shipAndLoadingBillDTOList = getAllShipBillById(vo.getShipbillId());
            ShipAndLoadingBillDTO realShipAndLoadingBillDTO = getRealShip(shipAndLoadingBillDTOList, vo.getShipbillId());
            log.info("realShipAndLoadingBillDTO={}", JSON.toJSONString(realShipAndLoadingBillDTO));
            batchSaveGps(shipAndLoadingBillDTOList, realShipAndLoadingBillDTO, vo, user);
        }
        //司机定位(只记录已启运到送达区间的gps)
        else {
            TmsVehicleGPSModel lastTmsVehicleGPSModel = tmsVehicleGPSMapper.findOneByCondition(user.getEnterpriseId(), user.getUserid(), "N");
            if (ObjectUtil.isNotNull(lastTmsVehicleGPSModel)) {
                Date lastDate = lastTmsVehicleGPSModel.getCreatetime();
                Integer locateInterval = getLocateInterval();
                //时间间隔大于配置的参数时才记录
                if (DateUtil.betweenMs(lastDate, new Date()) >= (locateInterval * 60 * 1000)) {
                    //查询已启运的gps记录
                    List<TmsVehicleGPSModel> tmsVehicleGPSModelList = tmsVehicleGPSMapper.getByCondition(user.getEnterpriseId(), user.getUserid());
                    if (CollectionUtil.isNotEmpty(tmsVehicleGPSModelList)) {
                        tmsVehicleGPSModelList.stream().map(TmsVehicleGPSModel::getShipbillId).distinct().forEach(shipbillId -> {
                            List<ShipAndLoadingBillDTO> shipAndLoadingBillDTOList = getAllShipBillById(shipbillId);
                            ShipAndLoadingBillDTO realShipAndLoadingBillDTO = getRealShip(shipAndLoadingBillDTOList, shipbillId);
                            log.info("realShipAndLoadingBillDTO={}", JSON.toJSONString(realShipAndLoadingBillDTO));
                            //非已送达的才记录gps
                            if(ObjectUtil.notEqual(realShipAndLoadingBillDTO.getStatus(),DataDictionaryConstant.SHIPBILL_STATUS_HD_ZB) &&
                                    ObjectUtil.notEqual(realShipAndLoadingBillDTO.getStatus(), DataDictionaryConstant.SHIPBILL_STATUS_HD_PIC) &&
                                    ObjectUtil.notEqual(realShipAndLoadingBillDTO.getStatus(),DataDictionaryConstant.SHIPBILL_STATUS_END)){
                                batchSaveGps(shipAndLoadingBillDTOList, realShipAndLoadingBillDTO, vo, user);
                            }
                        });
                    }
                }
            }
        }
    }

    /**
     * 获取当前真实的运单信息
     * @param shipAndLoadingBillDTOList
     * @param shipBillId
     * @return
     */
    private ShipAndLoadingBillDTO getRealShip(List<ShipAndLoadingBillDTO> shipAndLoadingBillDTOList, String shipBillId) {
        Optional<ShipAndLoadingBillDTO> shipAndLoadingBillDTOOptional = shipAndLoadingBillDTOList.stream().
                filter(shipAndLoadingBillDTO -> shipBillId.equals(shipAndLoadingBillDTO.getShipBillId())).findFirst();
        if (shipAndLoadingBillDTOOptional.isPresent()) {
            return shipAndLoadingBillDTOOptional.get();
        } else {
            throw new BizException("运单不存在=" + shipBillId);
        }
    }

    /**
     * 批量保存gps记录
     * @param shipAndLoadingBillDTOList
     * @param realShipAndLoadingBillDTO
     * @param vo
     * @param userEntity
     */
    private void batchSaveGps(List<ShipAndLoadingBillDTO> shipAndLoadingBillDTOList, ShipAndLoadingBillDTO realShipAndLoadingBillDTO,
                              VehicleGpsSaveVO vo, UserEntity userEntity) {
        Date date = new Date();
        List<TmsVehicleGPSModel> list = shipAndLoadingBillDTOList.stream().map(shipAndLoadingBillDTO -> {
            TmsVehicleGPSModel tmsVehicleGPSModel = new TmsVehicleGPSModel();
            tmsVehicleGPSModel.setId(RandomUtil.randomLong());
            tmsVehicleGPSModel.setShipbillId(shipAndLoadingBillDTO.getShipBillId());
            tmsVehicleGPSModel.setShipbillNo(shipAndLoadingBillDTO.getShipBillNo());
            tmsVehicleGPSModel.setLoadingbillId(shipAndLoadingBillDTO.getLoadingBillId());
            tmsVehicleGPSModel.setLoadingbillNo(shipAndLoadingBillDTO.getLoadingBillNo());
            tmsVehicleGPSModel.setVehicleId(realShipAndLoadingBillDTO.getVehicleId());
            tmsVehicleGPSModel.setVehicleCode(realShipAndLoadingBillDTO.getVehicleCode());
            tmsVehicleGPSModel.setVehiclePlateNumber(realShipAndLoadingBillDTO.getVehiclePlateNumber());
            tmsVehicleGPSModel.setDriverId(userEntity.getUserid());
            tmsVehicleGPSModel.setDriverCode(realShipAndLoadingBillDTO.getDriverCode());
            tmsVehicleGPSModel.setDriverName(realShipAndLoadingBillDTO.getDriverName());
            tmsVehicleGPSModel.setDriverPhoneNumber(realShipAndLoadingBillDTO.getDriverPhoneNumber());
            tmsVehicleGPSModel.setLongitude(vo.getLongitude());
            tmsVehicleGPSModel.setLatitude(vo.getLatitude());
            tmsVehicleGPSModel.setTemperature(vo.getTemperature());
            tmsVehicleGPSModel.setEnterpriseId(userEntity.getEnterpriseId());
            tmsVehicleGPSModel.setEnterpriseName(userEntity.getEnterpriseName());
            tmsVehicleGPSModel.setCreatetime(date);
            tmsVehicleGPSModel.setCreateperson(userEntity.getNickname());
            tmsVehicleGPSModel.setUpdatetime(date);
            tmsVehicleGPSModel.setUpdateperson(userEntity.getNickname());
            tmsVehicleGPSModel.setStartShipTime(vo.getStartShipTime());
            tmsVehicleGPSModel.setDeliveryTime(vo.getDeliveryTime());
            tmsVehicleGPSModel.setRealShipbillId(realShipAndLoadingBillDTO.getShipBillId());
            return tmsVehicleGPSModel;
        }).collect(Collectors.toList());
        log.info("batchSaveGps,list={}", JSON.toJSONString(list));
        tmsVehicleGPSMapper.saveBatch(list);
    }

    /**
     * 获取定位间隔参数
     * @return
     */
    private Integer getLocateInterval() {
        SysParamConfigModel sysParamConfig;
        try {
            sysParamConfig = sysParamConfigService.getValue(BussinessConstant.LOCATE_INTERVAL);
        } catch (Exception e) {
            throw new BizException(e.getMessage());
        }
        if(ToolKits.isEmpty(sysParamConfig)){
            throw new BizException("定位间隔参数查询失败");
        }
        String locateInterval = sysParamConfig.getValue();
        if (StrUtil.isBlank(locateInterval)) {
            throw new BizException("定位间隔参数为空");
        }
        log.info("getLocateInterval,locateInterval={}", locateInterval);
        return Integer.valueOf(locateInterval);
    }

    /**
     * 通过运单ID查询所有父级运单信息
     * @param shipBillId
     * @return
     */
    private List<ShipAndLoadingBillDTO> getAllShipBillById(String shipBillId) {
        RestMessage<List<ShipAndLoadingBillDTO>> msg = businessComingRecordFeign.getAllShipBillById(shipBillId);
        if (!msg.isSuccess()) {
            throw new BizException("运单信息查询接口调用失败：" + msg.getMessage());
        }
        if (CollectionUtil.isEmpty(msg.getData())) {
            throw new BizException("运单信息查询为空");
        }
        log.info("getAllShipBillById,shipBillId={},response={}", shipBillId, JSON.toJSONString(msg.getData()));
        return msg.getData();
    }

    //@Scheduled(cron="0 */1 * * * ?")//每分钟执行一次
    @Scheduled(cron="0 0 2 * * ?")//每天凌晨2点执行一次
    public void timedTask() throws Exception {
        //获取GPS数据保存天数参数
        SysParamConfigModel sysParamConfig=sysParamConfigService.getValueForTask(BussinessConstant.GPS_SAVE_DAYS);
        if(ToolKits.isEmpty(sysParamConfig)){
            throw new PrologException("定位间隔参数查询失败");
        }
        String value=sysParamConfig.getValue();
        Pattern pattern = Pattern.compile("[0-9]*");
        if(!(pattern.matcher(value).matches())){
            throw new PrologException("非法的系统参数,车辆轨迹数据保存期限(天)参数需为正整数!");
        }

        //拷贝GPS表至GPS历史表
        Date date=DateUtil.date();
        Calendar calendar=Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH,-(Integer.parseInt(value)));
        Date startdate=calendar.getTime();

        Criteria criteria = Criteria.forClass(TmsVehicleGPSModel.class);
        Restriction r1 = Restrictions.le("createtime", startdate);
//        Restriction r2 = Restrictions.le("createtime", date);
//        criteria.setRestriction(Restrictions.and(r1, r2));
        criteria.setRestriction(Restrictions.and(r1));
        List<TmsVehicleGPSModel> dataList = tmsVehicleGPSMapper.findByCriteria(criteria);

        for(TmsVehicleGPSModel tmsVehicleGPS:dataList){
            TmsVehicleGPSHistoryModel tmsVehicleGPSHistory=new TmsVehicleGPSHistoryModel();
            BeanUtils.copyProperties(tmsVehicleGPS,tmsVehicleGPSHistory);
            tmsVehicleGPSHistory.setId(new Random().nextLong());
            tmsVehicleGPSHistoryMapper.save(tmsVehicleGPSHistory);
            tmsVehicleGPSMapper.deleteById(tmsVehicleGPS.getId(),TmsVehicleGPSModel.class);
        }
    }

}
