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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.prolog.common.util.ToolKits;
import com.prolog.framework.core.exception.BizException;
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.DataDictionaryConstant;
import com.prolog.rdc.tms.dao.mapper.TmsGpsDataMapper;
import com.prolog.rdc.tms.model.dto.ShipbillHeaderPageDTO;
import com.prolog.rdc.tms.model.dto.intransit.DeviceGpsDTO;
import com.prolog.rdc.tms.model.dto.intransit.InTransitTrackDTO;
import com.prolog.rdc.tms.model.dto.intransit.LoadingAndShipBillHeaderDTO;
import com.prolog.rdc.tms.model.dto.intransit.LoadingBillHeaderPageDTO;
import com.prolog.rdc.tms.model.entity.TmsGpsDataModel;
import com.prolog.rdc.tms.model.entity.TmsLoadingBillDetailModel;
import com.prolog.rdc.tms.model.entity.TmsLoadingBillHeaderModel;
import com.prolog.rdc.tms.model.entity.TmsShipbillHeaderModel;
import com.prolog.rdc.tms.model.vo.intransit.InTransitQueryVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;


/**
 * @author hongbo.pan
 * @date 2022/9/20
 */
@Service
public class InTransitDeviceServiceImpl extends AbstractInTransit {

    @Autowired
    private TmsGpsDataMapper tmsGpsDataMapper;

    @Override
    public DeviceGpsDTO getPosition(InTransitQueryVO vo) {
        List<DeviceGpsDTO> deviceGpsDTOList = tmsLoadingBillHeaderMapper.getInTransitDeviceGps(vo);
        if (CollectionUtil.isEmpty(deviceGpsDTOList)) {
            throw new BizException("车辆设备定位不存在");
        }
        DeviceGpsDTO deviceGpsDTO = deviceGpsDTOList.get(deviceGpsDTOList.size() - 1);
        return setShipBillId(deviceGpsDTO);
    }

    @Override
    public List<DeviceGpsDTO> getTrack(InTransitQueryVO vo) {
        List<DeviceGpsDTO> deviceGpsDTOList = tmsLoadingBillHeaderMapper.getInTransitDeviceGps(vo);
        if (CollectionUtil.isEmpty(deviceGpsDTOList)) {
            throw new BizException("车辆设备轨迹不存在");
        }
        return  deviceGpsDTOList.stream().peek(deviceGpsDTO -> setShipBillId(deviceGpsDTO)).collect(Collectors.toList());
    }

    @Override
    public LoadingAndShipBillHeaderDTO getLoadingAndShipBillByGpsId(String gpsId) {
        return null;
    }

    /**
     * 运单设备定位
     * @param shipBillId
     * @return
     */
    @Override
    public DeviceGpsDTO getPositionByShipBillId(String shipBillId) {
        TmsShipbillHeaderModel tmsShipbillHeaderModel = checkShipBillAndReturn(shipBillId);
        /*if (StrUtil.isBlank(tmsShipbillHeaderModel.getVehicleDeviceCode())) {
            throw new BizException("当前运单["+tmsShipbillHeaderModel.getShipbillNo()+"]没有设备号");
        }*/
        List<DeviceGpsDTO> deviceGpsDTOList = getDeviceGpsByShipBillId(tmsShipbillHeaderModel);
        if (CollectionUtil.isEmpty(deviceGpsDTOList)) {
            throw new BizException(shipBillId + "运单设备定位不存在");
        }
        return deviceGpsDTOList.get(deviceGpsDTOList.size() - 1);
    }

    /**
     * 运单设备轨迹
     * @param shipBillId
     * @return
     */
    @Override
    public InTransitTrackDTO getTrackByShipBillId(String shipBillId) {
        TmsShipbillHeaderModel tmsShipbillHeaderModel = checkShipBillAndReturn(shipBillId);
        /*if (StrUtil.isBlank(tmsShipbillHeaderModel.getVehicleDeviceCode())) {
            throw new BizException("当前运单["+tmsShipbillHeaderModel.getShipbillNo()+"]没有设备号");
        }*/
        List<DeviceGpsDTO> deviceGpsDTOList = getDeviceGpsByShipBillId(tmsShipbillHeaderModel);
        if (CollectionUtil.isEmpty(deviceGpsDTOList)) {
            throw new BizException(shipBillId + "运单设备轨迹不存在");
        }
        InTransitTrackDTO inTransitTrackDTO = new InTransitTrackDTO();
        inTransitTrackDTO.setStatus(tmsShipbillHeaderModel.getStatus());
        if (tmsShipbillHeaderModel.getStatus() > DataDictionaryConstant.SHIPBILL_STATUS_SD) {
            inTransitTrackDTO.setDesc("终点");
        } else {
            inTransitTrackDTO.setDesc("在途");
        }
        inTransitTrackDTO.setDeviceGpsDTOList(deviceGpsDTOList);
        return inTransitTrackDTO;
    }

    @Override
    public DeviceGpsDTO getPositionByLoadingBillId(String loadingBillId) {
        TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel = checkLoadingBillAndReturn(loadingBillId);
        List<DeviceGpsDTO> deviceGpsDTOList = getDeviceGpsByLoadingBillId(tmsLoadingBillHeaderModel);
        if (CollectionUtil.isEmpty(deviceGpsDTOList)) {
            throw new BizException(loadingBillId + "派车设备定位不存在");
        }
        return deviceGpsDTOList.get(deviceGpsDTOList.size() - 1);
    }

    @Override
    public InTransitTrackDTO getTrackByLoadingBillId(String loadingBillId) {
        TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel = checkLoadingBillAndReturn(loadingBillId);
        List<DeviceGpsDTO> deviceGpsDTOList = getDeviceGpsByLoadingBillId(tmsLoadingBillHeaderModel);
        if (CollectionUtil.isEmpty(deviceGpsDTOList)) {
            throw new BizException(loadingBillId + "派车设备轨迹不存在");
        }
        InTransitTrackDTO inTransitTrackDTO = new InTransitTrackDTO();
        inTransitTrackDTO.setStatus(tmsLoadingBillHeaderModel.getStatus());
        if (tmsLoadingBillHeaderModel.getStatus() >= DataDictionaryConstant.LOADING_BILL_STATUS_SD) {
            inTransitTrackDTO.setDesc("终点");
        } else {
            inTransitTrackDTO.setDesc("在途");
        }
        inTransitTrackDTO.setDeviceGpsDTOList(deviceGpsDTOList);
        return inTransitTrackDTO;
    }

    /**
     * 派车单分页
     * @param vo
     * @return
     */
    @Override
    List<LoadingBillHeaderPageDTO> pageLoadingBillByPositionType(InTransitQueryVO vo) {
        return tmsLoadingBillHeaderMapper.getInTransitDeviceLoadingBill(vo);
    }

    /**
     * 运单分页
     * @param vo
     * @return
     */
    @Override
    List<ShipbillHeaderPageDTO> pageShipBillByPositionType(InTransitQueryVO vo) {
        return tmsShipbillHeaderMapper.getInTransitDeviceShipBill(vo);
    }

    /**
     * 根据运单获取设备gps数据
     * @param tmsShipbillHeaderModel
     * @return
     */
    private List<DeviceGpsDTO> getDeviceGpsByShipBillId(TmsShipbillHeaderModel tmsShipbillHeaderModel) {
        return getDeviceGpsByShipBillId(tmsShipbillHeaderModel, null);
    }

    /**
     * 根据运单获取设备gps数据
     * @param tmsShipbillHeaderModel
     * @param tmsLoadingBillHeaderModel
     * @return
     */
    private List<DeviceGpsDTO> getDeviceGpsByShipBillId(TmsShipbillHeaderModel tmsShipbillHeaderModel, TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        List<DeviceGpsDTO> deviceGpsDTOList = Lists.newArrayList();
        Criteria criteria = Criteria.forClass(TmsGpsDataModel.class);
        Restriction r1 = Restrictions.eq(TmsGpsDataModel::getDeviceCode, tmsShipbillHeaderModel.getShipbillId());
        Restriction r2 = Restrictions.eq(TmsGpsDataModel::getEnterpriseId, user.getEnterpriseId());
        Restriction r5 = Restrictions.in(TmsGpsDataModel::getVehiclePlateNumber, tmsShipbillHeaderModel.getExpressNumber().split(","));
        //Restriction r3 = ToolKits.isEmpty(tmsShipbillHeaderModel.getDepartureTime()) ? null : Restrictions.ge(TmsGpsDataModel::getGpsDate, tmsShipbillHeaderModel.getDepartureTime());
        //Restriction r4 = ToolKits.isEmpty(tmsShipbillHeaderModel.getDeliveryTime()) ? null : Restrictions.le(TmsGpsDataModel::getGpsDate, tmsShipbillHeaderModel.getDeliveryTime());
        criteria.setRestriction(Restrictions.and(r1, r2, r5));
        criteria.setOrder(Order.newInstance().asc(TmsGpsDataModel::getGpsDate));
        List<TmsGpsDataModel> tmsGpsDataModelList = tmsGpsDataMapper.findByCriteria(criteria);
        if (CollectionUtil.isNotEmpty(tmsGpsDataModelList)) {
            if (ObjectUtil.isNull(tmsLoadingBillHeaderModel)) {
                criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
                r1 = Restrictions.eq(TmsLoadingBillDetailModel::getShipbillId, tmsShipbillHeaderModel.getShipbillId());
                r2 = Restrictions.eq(TmsLoadingBillDetailModel::getEnterpriseId, user.getEnterpriseId());
                criteria.setRestriction(Restrictions.and(r1, r2));
                criteria.setOrder(Order.newInstance().desc(TmsLoadingBillDetailModel::getCreatetime));
                List<TmsLoadingBillDetailModel> loadingBillDetailModels = tmsLoadingBillDetailMapper.findByCriteria(criteria);
                ToolKits.isParamNull(loadingBillDetailModels, "未找到对应的调度单明细");
                TmsLoadingBillDetailModel loadingBillDetailModel = loadingBillDetailModels.get(0);
                tmsLoadingBillHeaderModel =
                        tmsLoadingBillHeaderMapper.findById(loadingBillDetailModel.getLoadingBillId(), TmsLoadingBillHeaderModel.class);
            }
            TmsLoadingBillHeaderModel finalTmsLoadingBillHeaderModel = tmsLoadingBillHeaderModel;
            deviceGpsDTOList = tmsGpsDataModelList.stream().map(model -> {
                DeviceGpsDTO dto = BeanUtil.toBean(model, DeviceGpsDTO.class);
                dto.setDriverId(finalTmsLoadingBillHeaderModel.getDriverId());
                dto.setDriverCode(finalTmsLoadingBillHeaderModel.getDriverCode());
                dto.setDriverName(finalTmsLoadingBillHeaderModel.getDriverName());
                dto.setDriverPhoneNumber(finalTmsLoadingBillHeaderModel.getDriverPhoneNumber());
                dto.setVehicleId(finalTmsLoadingBillHeaderModel.getVehicleId());
                dto.setVehicleCode(finalTmsLoadingBillHeaderModel.getVehicleCode());
                dto.setVehiclePlateNumber(finalTmsLoadingBillHeaderModel.getVehiclePlateNumber());
                dto.setShipbillId(tmsShipbillHeaderModel.getShipbillId());
                dto.setShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
                dto.setLoadingBillNo(finalTmsLoadingBillHeaderModel.getLoadingBillNo());
                dto.setLoadingBillId(finalTmsLoadingBillHeaderModel.getLoadingBillId());
                dto.setCurrentVelocity(BigDecimal.ZERO);
                dto.setVehicleDirection(BigDecimal.ZERO);
                return dto;
            }).collect(Collectors.toList());
            deviceGpsDTOList = deviceGpsDTOList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
                    new TreeSet<>(Comparator.comparing(DeviceGpsDTO::getGpsDate))), ArrayList::new));
        }
        return deviceGpsDTOList;
    }

    /**
     * 根据派车单获取设备gps数据
     * @param tmsLoadingBillHeaderModel
     * @return
     */
    private List<DeviceGpsDTO> getDeviceGpsByLoadingBillId(TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel) {
        List<TmsLoadingBillDetailModel> loadingBillDetailModels = findByLoadingBillId(tmsLoadingBillHeaderModel.getLoadingBillId());
        List<TmsShipbillHeaderModel> tmsShipbillHeaderModelList = tmsShipbillHeaderMapper.findByIds(TmsShipbillHeaderModel.class,
                loadingBillDetailModels.stream().map(TmsLoadingBillDetailModel::getShipbillId).toArray(), null);
        return tmsShipbillHeaderModelList.stream().flatMap(tmsShipbillHeaderModel ->
                getDeviceGpsByShipBillId(tmsShipbillHeaderModel, tmsLoadingBillHeaderModel).stream()).collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
                new TreeSet<>(Comparator.comparing(DeviceGpsDTO::getId))), ArrayList::new)).stream().sorted(
                Comparator.comparing(DeviceGpsDTO::getGpsDate)).collect(Collectors.toList());
    }

    /**
     * findByLoadingBillId
     * @param loadingBillId
     * @return
     */
    private List<TmsLoadingBillDetailModel> findByLoadingBillId(String loadingBillId) {
        Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
        Restriction r1 = Restrictions.eq(TmsLoadingBillDetailModel::getLoadingBillId, loadingBillId);
        criteria.setRestriction(Restrictions.and(r1));
        return tmsLoadingBillDetailMapper.findByCriteria(criteria);
    }

    /**
     * setShipBillId
     */
    private DeviceGpsDTO setShipBillId(DeviceGpsDTO deviceGpsDTO) {
        List<TmsLoadingBillDetailModel> loadingBillDetailModels = findByLoadingBillId(deviceGpsDTO.getLoadingBillId());
        if (CollectionUtil.isNotEmpty(loadingBillDetailModels)) {
            deviceGpsDTO.setShipbillNo(loadingBillDetailModels.stream().map(TmsLoadingBillDetailModel::getShipbillNo).distinct().collect(Collectors.joining(",")));
            deviceGpsDTO.setShipbillId(loadingBillDetailModels.stream().map(TmsLoadingBillDetailModel::getShipbillId).distinct().collect(Collectors.joining(",")));
        }
        return deviceGpsDTO;
    }

}