package com.prolog.rdc.tms.app.service.business.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
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.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.RestrictionBuilder;
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.app.constant.DataDictionaryConstant;
import com.prolog.rdc.tms.app.dao.mapper.TmsLoadingBillDetailMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsLoadingBillHeaderMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillHeaderMapper;
import com.prolog.rdc.tms.app.model.entity.TmsLoadingBillDetailModel;
import com.prolog.rdc.tms.app.model.entity.TmsLoadingBillHeaderModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillHeaderModel;
import com.prolog.rdc.tms.app.service.business.LoadingBillService;
import com.prolog.rdc.tms.model.dto.VehicleCheckDTO;
import com.prolog.rdc.tms.model.vo.fleetManagement.VehicleCheckVO;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author hongbo.pan
 * @date 2022/9/29
 */
@Slf4j
@Service
public class LoadingBillServiceImpl implements LoadingBillService {

	@Autowired
	private TmsLoadingBillHeaderMapper tmsLoadingBillHeaderMapper;

	@Autowired
	private TmsLoadingBillDetailMapper tmsLoadingBillDetailMapper;

	@Autowired
	private TmsShipbillHeaderMapper tmsShipbillHeaderMapper;

	@Autowired
	private MaindataFeign maindataTmsResource;

	/**
	 * 更新派车单站点数
	 * 
	 * @param loadingBillId
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateStationByLoadingBillId(String loadingBillId) {
		if (StrUtil.isNotBlank(loadingBillId)) {
			updateStationByLoadingBillIdList(Lists.newArrayList(loadingBillId));
		}
	}

	/**
	 * 批量更新派车单站点数
	 * 
	 * @param loadingBillIdList
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateStationByLoadingBillIdList(List<String> loadingBillIdList) {
		log.info("批量更新派车单站点数=" + JSON.toJSONString(loadingBillIdList));
		if (CollectionUtil.isNotEmpty(loadingBillIdList)) {
			Criteria criteria = new Criteria(TmsLoadingBillDetailModel.class);
			Restriction rt1 = new RestrictionBuilder().in("loadingBillId", loadingBillIdList.toArray()).build();
			criteria.setRestriction(rt1);
			// 根据派车单id集合查询明细
			List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
			if (CollectionUtil.isNotEmpty(tmsLoadingBillDetailModelList)) {
				// 明细按派车单分组
				Map<String, List<TmsLoadingBillDetailModel>> loadingBillMap = tmsLoadingBillDetailModelList.stream().collect(Collectors.groupingBy(TmsLoadingBillDetailModel::getLoadingBillId));
				List<String> shipBillIdList = loadingBillMap.values().stream().flatMap(list -> list.stream().filter(model -> StrUtil.isNotBlank(model.getShipbillId())).map(TmsLoadingBillDetailModel::getShipbillId)).collect(Collectors.toList());
				// 查询运单
				List<TmsShipbillHeaderModel> tmsShipBillHeaderModelList = tmsShipbillHeaderMapper.findByIds(TmsShipbillHeaderModel.class, shipBillIdList.toArray(), null);
				if (CollectionUtil.isNotEmpty(tmsShipBillHeaderModelList)) {
					// 按派车单统计站点数并更新
					loadingBillMap.forEach((key, value) -> {
						log.info("更新派车单站点数key=" + key + ",value=" + JSON.toJSONString(value));
						if (CollectionUtil.isNotEmpty(value)) {
							List<String> idList = value.stream().filter(model -> StrUtil.isNotBlank(model.getShipbillId())).map(TmsLoadingBillDetailModel::getShipbillId).collect(Collectors.toList());
							List<TmsShipbillHeaderModel> filterShipBillHeaderModelList = tmsShipBillHeaderModelList.stream().filter(tmsShipBillHeaderModel -> idList.contains(tmsShipBillHeaderModel.getShipbillId())).collect(Collectors.toList());
							log.info("派车单=" + key + ",对应运单id=" + JSON.toJSONString(idList));
							log.info("派车单=" + key + ",对应运单=" + JSON.toJSONString(filterShipBillHeaderModelList));
							Map<String, Object> updateMap = Maps.newHashMap();
							updateMap.put("pickupStations", 0L);
							updateMap.put("deliveryStations", 0L);
							updateMap.put("totalStations", 0L);
							updateMap.put("cargoOwnerNumber", 0L);
							updateMap.put("coldShipbillNumber", 0L);
							updateMap.put("urgentShipbillNumber", 0L);
							updateMap.put("shipbillNumber", 0L);
							updateMap.put("customerNumber", 0L);
							updateMap.put("updatetime", new Date());
							if (CollectionUtil.isNotEmpty(filterShipBillHeaderModelList)) {
								long pickupStations = filterShipBillHeaderModelList.stream().filter(model -> StrUtil.isNotBlank(model.getShipperAddress())).map(TmsShipbillHeaderModel::getShipperAddress).map(StrUtil::trim).distinct().count();
								long deliveryStations = filterShipBillHeaderModelList.stream().filter(model -> StrUtil.isNotBlank(model.getConsigneeAddress())).map(TmsShipbillHeaderModel::getConsigneeAddress).map(StrUtil::trim).distinct().count();
								long totalStations = pickupStations + deliveryStations;
								updateMap.put("pickupStations", pickupStations);
								updateMap.put("deliveryStations", deliveryStations);
								updateMap.put("totalStations", totalStations);
								updateMap.put("cargoOwnerNumber", filterShipBillHeaderModelList.stream().map(TmsShipbillHeaderModel::getCargoOwnerId).filter(ObjectUtil::isNotNull).distinct().count());
								updateMap.put("coldShipbillNumber", filterShipBillHeaderModelList.stream().map(TmsShipbillHeaderModel::getTemperatureRequirement).filter(temperatureRequirement -> ObjectUtil.isNotNull(temperatureRequirement) && !DataDictionaryConstant.TEMPERATURE_REQUIREMENT_CW.equals(temperatureRequirement)).count());
								updateMap.put("urgentShipbillNumber", filterShipBillHeaderModelList.stream().map(TmsShipbillHeaderModel::getOrderType).filter(orderType -> ObjectUtil.isNotNull(orderType) && !DataDictionaryConstant.ORDER_TYPE_P.equals(orderType)).count());
								updateMap.put("shipbillNumber", filterShipBillHeaderModelList.size());
								updateMap.put("customerNumber", filterShipBillHeaderModelList.stream().filter(o -> ToolKits.isNotEmpty(o.getConsigneeName())).map(TmsShipbillHeaderModel::getConsigneeName).distinct().count());
							}
							log.info("更新派车单=" + key + ",站点数=" + JSON.toJSONString(updateMap));
							tmsLoadingBillHeaderMapper.updateMapById(key, updateMap, TmsLoadingBillHeaderModel.class);
						}
					});
				}
			}
		}
	}

	/**
	 * 获取派车单号
	 * 
	 * @param shipBillId
	 * @return
	 */
	@Override
	public String getLoadingBillIdByShipBillId(String shipBillId) {
		Criteria criteria = new Criteria(TmsLoadingBillDetailModel.class);
		Restriction rt1 = new RestrictionBuilder().eq("shipbillId", shipBillId).build();
		criteria.setRestriction(rt1);
		criteria.orderDescBy("createtime");
		List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
		if (CollectionUtil.isNotEmpty(tmsLoadingBillDetailModelList)) {
			return tmsLoadingBillDetailModelList.get(0).getLoadingBillId();
		}
		return StrUtil.EMPTY;
	}

	/**
	 * 获取派车单号
	 * 
	 * @param shipBillIds
	 * @return
	 */
	@Override
	public List<String> getLoadingBillIdsByShipBillIds(List<String> shipBillIds) {
		if (CollectionUtil.isEmpty(shipBillIds)) {
			return Lists.newArrayList();
		}
		return shipBillIds.stream().map(shipBillId -> getLoadingBillIdByShipBillId(shipBillId)).filter(StrUtil::isNotBlank).collect(Collectors.toList());
	}

	/**
	 * 更新派车单
	 * 
	 * @param loadingBillIdList
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void reCalLoadingBill(List<String> loadingBillIdList) {
		if (CollectionUtil.isEmpty(loadingBillIdList)) {
			return;
		}
		loadingBillIdList = loadingBillIdList.stream().distinct().collect(Collectors.toList());
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		List<TmsLoadingBillHeaderModel> tmsLoadingBillHeaderModelList = tmsLoadingBillHeaderMapper.findByIds(TmsLoadingBillHeaderModel.class, loadingBillIdList.toArray(), null);
		tmsLoadingBillHeaderModelList.forEach(tmsLoadingBillHeaderModel -> {
			Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
			Restriction restriction = Restrictions.eq("loadingBillId", tmsLoadingBillHeaderModel.getLoadingBillId());
			criteria.setRestriction(restriction);
			List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
			if (CollectionUtil.isEmpty(tmsLoadingBillDetailModelList)) {
				// 重量体积件数
				tmsLoadingBillHeaderModel.setTotalPcs(BigDecimal.ZERO);
				tmsLoadingBillHeaderModel.setTotalVolume(BigDecimal.ZERO);
				tmsLoadingBillHeaderModel.setTotalWeight(BigDecimal.ZERO);
				// 实际重量体积件数
				tmsLoadingBillHeaderModel.setActualTotalPcs(BigDecimal.ZERO);
				tmsLoadingBillHeaderModel.setActualTotalVolume(BigDecimal.ZERO);
				tmsLoadingBillHeaderModel.setActualTotalWeight(BigDecimal.ZERO);
				// 整件数拼箱数
				tmsLoadingBillHeaderModel.setTotalWholePiece(BigDecimal.ZERO);
				tmsLoadingBillHeaderModel.setTotalLclPiece(BigDecimal.ZERO);
				// 运单数
				tmsLoadingBillHeaderModel.setShipbillNumber(0);
				// 客户数
				tmsLoadingBillHeaderModel.setCustomerNumber(0);
				tmsLoadingBillHeaderModel.setPickupStations(0L);
				tmsLoadingBillHeaderModel.setDeliveryStations(0L);
				tmsLoadingBillHeaderModel.setTotalStations(0L);
				tmsLoadingBillHeaderModel.setCargoOwnerNumber(0L);
				tmsLoadingBillHeaderModel.setColdShipbillNumber(0L);
				tmsLoadingBillHeaderModel.setUrgentShipbillNumber(0L);
				// 计算装载率
				if (ToolKits.isNotEmpty(tmsLoadingBillHeaderModel.getVehicleId())) {
					tmsLoadingBillHeaderModel.setVolumeLoadingRate("0%");
					tmsLoadingBillHeaderModel.setWeightLoadingRate("0%");
				}
			} else {
				tmsLoadingBillHeaderModel.setTotalPcs(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getTotalPcs).reduce(BigDecimal.ZERO, NumberUtil::add));
				tmsLoadingBillHeaderModel.setTotalVolume(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getTotalVolume).reduce(BigDecimal.ZERO, NumberUtil::add));
				tmsLoadingBillHeaderModel.setTotalWeight(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getTotalWeight).reduce(BigDecimal.ZERO, NumberUtil::add));
				tmsLoadingBillHeaderModel.setActualTotalPcs(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getActualTotalPcs).reduce(BigDecimal.ZERO, NumberUtil::add));
				tmsLoadingBillHeaderModel.setActualTotalVolume(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getActualTotalVolume).reduce(BigDecimal.ZERO, NumberUtil::add));
				tmsLoadingBillHeaderModel.setActualTotalWeight(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getActualTotalWeight).reduce(BigDecimal.ZERO, NumberUtil::add));
				tmsLoadingBillHeaderModel.setTotalWholePiece(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getPackageWholePiece).reduce(BigDecimal.ZERO, NumberUtil::add));
				tmsLoadingBillHeaderModel.setTotalLclPiece(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getPackageLclPiece).reduce(BigDecimal.ZERO, NumberUtil::add));
				tmsLoadingBillHeaderModel.setShipbillNumber(tmsLoadingBillDetailModelList.size());
				tmsLoadingBillHeaderModel.setCustomerNumber(tmsLoadingBillDetailModelList.stream().filter(o -> ToolKits.isNotEmpty(o.getConsigneeName())).map(TmsLoadingBillDetailModel::getConsigneeName).distinct().collect(Collectors.toList()).size());
				tmsLoadingBillHeaderModel.setPickupStations(tmsLoadingBillDetailModelList.stream().filter(model -> StrUtil.isNotBlank(model.getShipperAddress())).map(TmsLoadingBillDetailModel::getShipperAddress).map(StrUtil::trim).distinct().count());
				tmsLoadingBillHeaderModel.setDeliveryStations(tmsLoadingBillDetailModelList.stream().filter(model -> StrUtil.isNotBlank(model.getConsigneeAddress())).map(TmsLoadingBillDetailModel::getConsigneeAddress).map(StrUtil::trim).distinct().count());
				tmsLoadingBillHeaderModel.setTotalStations(tmsLoadingBillHeaderModel.getPickupStations() + tmsLoadingBillHeaderModel.getDeliveryStations());
				tmsLoadingBillHeaderModel.setCargoOwnerNumber(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getCargoOwnerId).filter(ObjectUtil::isNotNull).distinct().count());
				tmsLoadingBillHeaderModel.setColdShipbillNumber(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getTemperatureRequirement).filter(temperatureRequirement -> ObjectUtil.isNotNull(temperatureRequirement) && !DataDictionaryConstant.TEMPERATURE_REQUIREMENT_CW.equals(temperatureRequirement)).count());
				tmsLoadingBillHeaderModel.setUrgentShipbillNumber(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getOrderType).filter(orderType -> ObjectUtil.isNotNull(orderType) && !DataDictionaryConstant.ORDER_TYPE_P.equals(orderType)).count());
				if (ToolKits.isNotEmpty(tmsLoadingBillHeaderModel.getVehicleId())) {
					Map<String, String> map = calculateLoadingRate(tmsLoadingBillHeaderModel.getVehicleId(), tmsLoadingBillHeaderModel.getTotalWeight(), tmsLoadingBillHeaderModel.getTotalVolume());
					tmsLoadingBillHeaderModel.setVolumeLoadingRate(map.get("volume"));
					tmsLoadingBillHeaderModel.setWeightLoadingRate(map.get("weight"));
				}
			}
			tmsLoadingBillHeaderModel.setUpdatetime(new Date());
			tmsLoadingBillHeaderModel.setUpdateperson(user.getNickname());
			tmsLoadingBillHeaderMapper.update(tmsLoadingBillHeaderModel);
		});
	}

	@Override
	public TmsLoadingBillHeaderModel setLoadingBillDelivery(TmsLoadingBillHeaderModel loadingBillHeaderModel) {
		Criteria criteria = new Criteria(TmsLoadingBillDetailModel.class);
		Restriction rt1 = new RestrictionBuilder()
				.eq(TmsLoadingBillDetailModel::getLoadingBillId, loadingBillHeaderModel.getLoadingBillId())
				.build();
		criteria.setRestriction(rt1);
		//根据派车单id集合查询明细
		List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
		if (CollectionUtil.isNotEmpty(tmsLoadingBillDetailModelList)) {
			loadingBillHeaderModel.setTotalDeliveryPcs(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getTotalDeliveryPcs).reduce(BigDecimal.ZERO, NumberUtil::add));
			loadingBillHeaderModel.setTotalDeliveryWeight(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getTotalDeliveryWeight).reduce(BigDecimal.ZERO, NumberUtil::add));
			loadingBillHeaderModel.setTotalDeliveryVolume(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getTotalDeliveryVolume).reduce(BigDecimal.ZERO, NumberUtil::add));
		}
		return loadingBillHeaderModel;
	}

	/**
	 * 计算装载率
	 * 
	 * @param id
	 * @param weight
	 * @param volume
	 * @return
	 */
	private Map<String, String> calculateLoadingRate(Long id, BigDecimal weight, BigDecimal volume) {
		VehicleCheckVO vehicleCheckVO = new VehicleCheckVO();
		vehicleCheckVO.setVehicleId(id);
		RestMessage<VehicleCheckDTO> data = maindataTmsResource.getVehicle(vehicleCheckVO);
		if (!data.isSuccess()) {
			throw new BizException("获取车辆失败");
		}
		VehicleCheckDTO vehicleCheckDTO = data.getData();
		StringBuilder weightStr = new StringBuilder();
		StringBuilder volumeStr = new StringBuilder();
		if (ToolKits.isNotEmpty(weight)) {
			BigDecimal divide = ToolKits.isEmpty(vehicleCheckDTO.getWeight()) ? BigDecimal.ZERO : weight.divide(vehicleCheckDTO.getWeight(), 2, BigDecimal.ROUND_HALF_UP);
			BigDecimal multiply = divide.multiply(new BigDecimal("100"));
			weightStr.append(multiply.intValue());
			weightStr.append("%");
		}
		if (ToolKits.isNotEmpty(volume)) {
			BigDecimal divide = ToolKits.isEmpty(vehicleCheckDTO.getVolume()) ? BigDecimal.ZERO : volume.divide(vehicleCheckDTO.getVolume(), 2, BigDecimal.ROUND_HALF_UP);
			BigDecimal multiply = divide.multiply(new BigDecimal("100"));
			volumeStr.append(multiply.intValue());
			volumeStr.append("%");
		}
		Map<String, String> map = Maps.newHashMap();
		map.put("weight", weightStr.toString());
		map.put("volume", volumeStr.toString());
		return map;
	}
}
