package com.yeejoin.equipmanage.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.util.StringUtil;
import com.google.common.collect.Lists;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.component.feign.config.InnerInvokException;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.equipmanage.common.datasync.entity.FireVehicle;
import com.yeejoin.equipmanage.common.dto.CarFusionDto;
import com.yeejoin.equipmanage.common.dto.CarInfoDto;
import com.yeejoin.equipmanage.common.dto.CarStatusInfoDto;
import com.yeejoin.equipmanage.common.entity.Car;
import com.yeejoin.equipmanage.common.entity.CarInfo;
import com.yeejoin.equipmanage.common.entity.CarProperty;
import com.yeejoin.equipmanage.common.entity.Equipment;
import com.yeejoin.equipmanage.common.entity.EquipmentCategory;
import com.yeejoin.equipmanage.common.entity.EquipmentDetail;
import com.yeejoin.equipmanage.common.entity.EquipmentIndex;
import com.yeejoin.equipmanage.common.entity.EquipmentOnCar;
import com.yeejoin.equipmanage.common.entity.EquipmentQrcode;
import com.yeejoin.equipmanage.common.entity.EquipmentSpecific;
import com.yeejoin.equipmanage.common.entity.ExtinguishantOnCar;
import com.yeejoin.equipmanage.common.entity.Journal;
import com.yeejoin.equipmanage.common.entity.ManufacturerInfo;
import com.yeejoin.equipmanage.common.entity.Stock;
import com.yeejoin.equipmanage.common.entity.StockDetail;
import com.yeejoin.equipmanage.common.entity.SystemDic;
import com.yeejoin.equipmanage.common.entity.Unit;
import com.yeejoin.equipmanage.common.entity.UploadFile;
import com.yeejoin.equipmanage.common.entity.WarehouseStructure;
import com.yeejoin.equipmanage.common.entity.WastageBill;
import com.yeejoin.equipmanage.common.entity.WastageBillDetail;
import com.yeejoin.equipmanage.common.entity.dto.CarDto;
import com.yeejoin.equipmanage.common.entity.publics.BaseEntity;
import com.yeejoin.equipmanage.common.entity.vo.CarIndexVo;
import com.yeejoin.equipmanage.common.entity.vo.CarPropertyVo;
import com.yeejoin.equipmanage.common.entity.vo.EquipmentSpecificVo;
import com.yeejoin.equipmanage.common.enums.BillContentEnum;
import com.yeejoin.equipmanage.common.enums.CarStatusEnum;
import com.yeejoin.equipmanage.common.enums.EquipStatusEnum;
import com.yeejoin.equipmanage.common.enums.FileTypeEnum;
import com.yeejoin.equipmanage.common.enums.IndustryEnum;
import com.yeejoin.equipmanage.common.enums.JournalTypeEnum;
import com.yeejoin.equipmanage.common.enums.OnBoardEquipmentEnum;
import com.yeejoin.equipmanage.common.enums.StockBillTypeEnum;
import com.yeejoin.equipmanage.common.enums.TrueOrFalseEnum;
import com.yeejoin.equipmanage.common.exception.CommonException;
import com.yeejoin.equipmanage.common.utils.ArrayUtil;
import com.yeejoin.equipmanage.common.utils.BillCodeManagerUtil;
import com.yeejoin.equipmanage.common.utils.DateUtils;
import com.yeejoin.equipmanage.common.utils.ParsePropertyUtil;
import com.yeejoin.equipmanage.common.utils.QRCodeUtil;
import com.yeejoin.equipmanage.common.vo.CarForUE4VO;
import com.yeejoin.equipmanage.common.vo.Equip;
import com.yeejoin.equipmanage.common.vo.EquipStateOnCarVo;
import com.yeejoin.equipmanage.common.vo.ExtinguishantLossRequest;
import com.yeejoin.equipmanage.common.vo.ExtinguishantRequeset;
import com.yeejoin.equipmanage.common.vo.OnBoardEquipment;
import com.yeejoin.equipmanage.mapper.CarInfoMapper;
import com.yeejoin.equipmanage.mapper.CarMapper;
import com.yeejoin.equipmanage.mapper.EquipmentCategoryMapper;
import com.yeejoin.equipmanage.mapper.EquipmentDetailMapper;
import com.yeejoin.equipmanage.mapper.EquipmentOnCarMapper;
import com.yeejoin.equipmanage.mapper.EquipmentSpecificMapper;
import com.yeejoin.equipmanage.mapper.ExtinguishantOnCarMapper;
import com.yeejoin.equipmanage.mapper.JournalMapper;
import com.yeejoin.equipmanage.mapper.StockDetailMapper;
import com.yeejoin.equipmanage.mapper.StockMapper;
import com.yeejoin.equipmanage.mapper.SystemDicMapper;
import com.yeejoin.equipmanage.mapper.UnitMapper;
import com.yeejoin.equipmanage.mapper.WarehouseStructureMapper;
import com.yeejoin.equipmanage.mapper.WastageBillDetailMapper;
import com.yeejoin.equipmanage.mapper.WastageBillMapper;
import com.yeejoin.equipmanage.remote.RemoteSecurityService;
import com.yeejoin.equipmanage.service.ICarPropertyService;
import com.yeejoin.equipmanage.service.ICarService;
import com.yeejoin.equipmanage.service.IEquipmentCategoryService;
import com.yeejoin.equipmanage.service.IEquipmentDetailService;
import com.yeejoin.equipmanage.service.IEquipmentIndexService;
import com.yeejoin.equipmanage.service.IEquipmentQrcodeService;
import com.yeejoin.equipmanage.service.IEquipmentService;
import com.yeejoin.equipmanage.service.IJournalService;
import com.yeejoin.equipmanage.service.IManufacturerInfoService;
import com.yeejoin.equipmanage.service.ISyncDataService;
import com.yeejoin.equipmanage.service.ISystemDicService;
import com.yeejoin.equipmanage.service.IUnitService;
import com.yeejoin.equipmanage.service.IUploadFileService;

/**
 * 消防车信息 服务实现类
 *
 * @author wujiang
 * @date 2020-07-07
 */
@Service
public class CarServiceImpl extends ServiceImpl<CarMapper, Car> implements ICarService {

    @Autowired
    private EquipmentCategoryMapper equipmentCategoryMapper;
    private List<Consumer<LossParams>> lossHandlers;
    private List<Consumer<LoadingParams>> loadingHandlers;
    @Autowired
    private CarInfoMapper carInfoMapper;
    @Autowired
    private ISystemDicService iSystemDicService;
    @Autowired
    private StockDetailMapper stockDetailMapper;
    @Autowired
    private SystemDicMapper systemDicMapper;
    @Autowired
    private IEquipmentQrcodeService iEquipmentQrcodeService;
    @Autowired
    private ExtinguishantOnCarMapper extinguishantOnCarMapper;
    @Autowired
    private CarMapper carMapper;
    @Autowired
    private WastageBillMapper wastageBillMapper;
    @Autowired
    private EquipmentDetailMapper equipmentDetailMapper;
    @Autowired
    private WastageBillDetailMapper wastageBillDetailMapper;
    @Autowired
    private JournalMapper journalMapper;
    @Autowired
    private ICarPropertyService iCarPropertyService;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private UnitMapper unitMapper;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private EquipmentOnCarMapper equipmentOnCarMapper;
    @Autowired
    private WarehouseStructureMapper warehouseStructureMapper;
    @Autowired
    protected HttpServletRequest request;
    @Autowired
    private IEquipmentService iEquipmentService;
    @Autowired
    private IUploadFileService iUploadFileService;
    @Autowired
    private IUnitService iUnitService;
    @Autowired
    @Lazy
    private IEquipmentIndexService equipmentIndexService;
    @Value("${fileserver_domain}")
    private String fileServer;
    @Autowired
    private IManufacturerInfoService iManufacturerInfoService;
    @Autowired
    private IJournalService journalService;

    @Autowired
    EquipmentSpecificMapper equipmentSpecificMapper;

    @Autowired
    private RemoteSecurityService remoteSecurityService;

    @Autowired
    private ICarPropertyService carPropertyService;

    @Autowired
    ISyncDataService syncDataService;
    @Autowired
    private IEquipmentDetailService iEquipmentDetailService;

    @Autowired
    private IEquipmentCategoryService iEquipmentCategoryService;
    

    @Value("${equip.dict.car-state}")
    private String carState;

    @Value("${equip.dict.name-key}")
    private String nameKeys;

    @Value("${systemctl.sync.switch}")
    private Boolean syncSwitch;

    /**
     * 当前登录用户信息
     */
    protected ReginParams getSelectedOrgInfo() {
        return JSONObject.parseObject(redisUtils.get(buildKey(getUserId(), getToken())).toString(), ReginParams.class);
    }

    protected String getUserId() {
        String userId = null;
        if (getUser() != null) {
            userId = getUser().getUserId();
        }
        return userId;
    }

    // redi缓存选择的用户信息
    private String buildKey(String userId, String token) {
        return RedisKey.buildReginKey(userId, token);

    }

    protected AgencyUserModel getUser() {
        AgencyUserModel userModel = null;
        if (getToken() != null) {
            RequestContext.setToken(getToken());
            RequestContext.setProduct(getProduct());
            RequestContext.setAppKey(getAppKey());
            FeignClientResult<?> feignClientResult;
            try {
                feignClientResult = Privilege.agencyUserClient.getme();
                userModel = (AgencyUserModel) feignClientResult.getResult();

            } catch (InnerInvokException e) {
                throw new RuntimeException(e.getMessage());
            }

        }
        return userModel;
    }

    protected String getToken() {
        String authToken = request.getHeader("token");
        if (authToken == null) {
            authToken = request.getHeader("X-Access-Token");
        }
        return authToken;
    }

    protected String getProduct() {
        String authToken = request.getHeader("product");
        if (authToken == null) {
            authToken = request.getParameter("product");
        }
        return authToken;
    }

    protected String getAppKey() {
        String authToken = request.getHeader("appKey");
        if (authToken == null) {
            authToken = request.getParameter("appKey");
        }
        return authToken;
    }

    protected String getChannelType() {
        String channelType = request.getHeader("channelType");
        if (channelType == null) {
            channelType = request.getParameter("channelType");
        }
        return channelType;
    }

    @Override
    public List<EquipmentCategory> getCarCategory() {
        List<EquipmentCategory> results = new ArrayList<>();
        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("name", "消防车");
        columnMap.put("industry_code", IndustryEnum.EQUIP.getCode());
        List<EquipmentCategory> equipmentCategory = equipmentCategoryMapper.selectByMap(columnMap);
        if (ObjectUtils.isEmpty(equipmentCategory)) {
            return results;
        }
        List<Map<String, Object>> lists = equipmentCategoryMapper
                .getEquipCategoryListByParentId(equipmentCategory.get(0).getId());
        for (Map<String, Object> map : lists) {
            EquipmentCategory instance = new EquipmentCategory();
            instance.setId(Long.parseLong(map.get("id").toString()));
            instance.setCode(map.get("code").toString());
            if (map.get("parentId") != null && StringUtil.isNotEmpty(map.get("parentId").toString())) {
                instance.setParentId(Long.parseLong(map.get("parentId").toString()));
            }
            instance.setName(map.get("name").toString());
            instance.setIsConsumptive(Boolean.valueOf(map.get("isConsumptive").toString()));
            instance.setLevel(String.valueOf(map.get("curLevel").toString()));
            results.add(instance);
        }
        return results;
    }

    @Override
    public Car saveCar(AgencyUserModel user, Car car, CarInfo carInfo, Set<CarProperty> carpList) {
        Car carInstance = saveCarInstance(user, car);
        if (carInstance == null) {
            throw new CommonException(0, "车辆信息保存失败");
        }
        Long carId = carInstance.getId();
        if (carInfo != null) {
            carInfo.setCarId(carId);
            carInfoMapper.insert(carInfo); // 保存车辆信息
        }
        if (carpList != null && !carpList.isEmpty()) {
            saveCarProperty(carpList, carInstance); // 保存性能指标
        }
        return carInstance;
    }

    private Car saveCarInstance(AgencyUserModel user, Car car) {
        if (car.getEquipmentId() == null) {
            throw new CommonException(0, "请选择车辆定义");
        }
        if (car.getCountry() == null) {
            throw new CommonException(0, "请填写国别");
        }
        if (car.getCarNum() == null) {
            throw new CommonException(0, "请填写车牌号");
        }
        QueryWrapper<Car> queryWrapper = new QueryWrapper<Car>();
        queryWrapper.lambda().eq(Car::getCarNum, car.getCarNum());
        List<Car> ifExistList = this.list(queryWrapper);
        if (car.getId() == null) {
            if (ifExistList != null && !ifExistList.isEmpty()) {
                throw new CommonException(0, "录入的车牌号已存在");
            }
        } else {
            List<Long> ids = new ArrayList<Long>();
            ifExistList.forEach(action -> ids.add(action.getId()));
            if (ifExistList != null && !ids.isEmpty() && !ids.contains(car.getId())) {
                throw new CommonException(0, "录入的车牌号已存在");
            }
        }

        if (car.getCarState() == null) {
//			SystemDic carState = iSystemDicService.findByTypeAndCode(SystemDicTypeEum.carState.getType(),
//					CarStatusEnum.ZW.getCode());
            car.setCarState(CarStatusEnum.ZW.getCode());
        }

        if (car.getId() != null) {
            Car oldcar = this.getById(car.getId());
            // 更新图片或者视频 删除远程服务器的文件
            // if (FtpUtil.isFastdfs&&oldcar!=null) {
            // if (StringUtil.isNotEmpty(oldcar.getImg()) &&
            // !oldcar.getImg().equals(car.getImg())) {
            // FtpUtil.ftpDeleteFileFastdfs(oldcar.getImg());
            // }
            // if (StringUtil.isNotEmpty(oldcar.getFilm()) &&
            // !oldcar.getFilm().equals(car.getFilm())) {
            // FtpUtil.ftpDeleteFileFastdfs(oldcar.getFilm());
            // }
            // }
        }
        this.save(car);
        saveCarQRCode(car);
        return car;
    }

    private void saveCarQRCode(Car car) {
        QueryWrapper<EquipmentQrcode> queryWrapper = new QueryWrapper<EquipmentQrcode>();
        queryWrapper.lambda().eq(EquipmentQrcode::getCarId, car.getId());
        List<EquipmentQrcode> equipmentQRCodeList = iEquipmentQrcodeService.getBaseMapper().selectList(queryWrapper);
        if (equipmentQRCodeList == null || equipmentQRCodeList.isEmpty()) {
            EquipmentQrcode equipmentQRCode = new EquipmentQrcode();
            equipmentQRCode.setCarId(car.getId());
            equipmentQRCode.setIsSingleUsed(true);
            iEquipmentQrcodeService.save(equipmentQRCode);
            if (StringUtils.isBlank(car.getQrCode())) {
                equipmentQRCode.setQRCode(QRCodeUtil.generateQRCode());
                car.setQrCode(equipmentQRCode.getQRCode());
            } else {
                equipmentQRCode.setQRCode(car.getQrCode());
            }
            this.save(car);
            iEquipmentQrcodeService.save(equipmentQRCode);
        } else {
            if (!StringUtil.isNotEmpty(car.getQrCode())) {
                car.setQrCode(equipmentQRCodeList.get(0).getQRCode());
                this.save(car);
            }
        }
    }

    private void saveCarProperty(Set<CarProperty> carpList, Car car) {
        carpList.forEach(action -> {
            if (action.getCarId() == null) {
                if (action.getValue() != null) {
                    CarProperty carPro = new CarProperty();
                    carPro.setCarId(car.getId());
                    // carPro.setPerfQuotaDefinitionId(action.getPerfQuotaDefinitionId());
                    carPro.setValue(action.getValue());
                    carPro.setRemark(action.getRemark());
                    iCarPropertyService.save(carPro);
                }
            } else {
                iCarPropertyService.save(action);
            }
        });
    }

    // 消耗灭火药剂
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> lossExtinguishants(Long carId, List<ExtinguishantLossRequest> extinguishants) {
        LossParams params = new LossParams(carId, extinguishants);
        lossHandlers.forEach(handler -> handler.accept(params));
        Map<String, String> result = new HashMap<>();
        result.put("person", getUser().getRealName());
        result.put("time", DateUtils.getNowStrLong());
        result.put("number", params.getBill().getBillCode());
        return result;
    }

    class LossParams {
        private Long carId;

        private Long lossStateId;

        private List<ExtinguishantLossRequest> extinguishants;

        private Car car;

        private Map<Long, StockDetail> details;

        private List<ExtinguishantOnCar> extinguishantOnCar;

        /**
         * 记录明细账id,用户更新搜索
         */
        private Set<Long> stockDetailIds;

        /**
         * 损耗单
         */
        private WastageBill bill;

        public LossParams(Long carId, List<ExtinguishantLossRequest> extinguishants) {
            this.carId = carId;
            this.extinguishants = extinguishants;
            setStockDetailIds(new HashSet<>());
        }

        public StockDetail getDetailById(Long id) {
            return details.get(id);
        }

        public Long getCarId() {
            return carId;
        }

        public void setCarId(Long carId) {
            this.carId = carId;
        }

        public List<ExtinguishantLossRequest> getExtinguishants() {
            return extinguishants;
        }

        public void setExtinguishants(List<ExtinguishantLossRequest> extinguishants) {
            this.extinguishants = extinguishants;
        }

        public Car getCar() {
            return car;
        }

        public void setCar(Car car) {
            this.car = car;
        }

        public Map<Long, StockDetail> getDetails() {
            return details;
        }

        public void setDetails(Map<Long, StockDetail> details) {
            this.details = details;
        }

        public List<ExtinguishantOnCar> getExtinguishantOnCar() {
            return extinguishantOnCar;
        }

        public void setExtinguishantOnCar(List<ExtinguishantOnCar> extinguishantOnCar) {
            this.extinguishantOnCar = extinguishantOnCar;
        }

        public WastageBill getBill() {
            return bill;
        }

        public void setBill(WastageBill bill) {
            this.bill = bill;
        }

        private Double equalLossCountHandler(ExtinguishantOnCar ex, Double lossCount) throws Exception {
            try {
                StockDetail stockDetail = getDetailById(ex.getStockDetailId());
                stockDetail.setStatus(EquipStatusEnum.LOSS.getCode().toString());
                stockDetail.setId(null);
                stockDetailMapper.insert(stockDetail);
                addStockDetailId(stockDetail.getId());
                // 查询库存
                Stock stock = stockMapper.selectById(stockDetail.getStockId());
                stock.setAmount(stock.getAmount() - lossCount);
                stockMapper.updateById(stock);
                // 删除
                extinguishantOnCarMapper.deleteById(ex.getId());
                // 损耗清单详情
                WastageBillDetail detail = new WastageBillDetail();
                detail.setAmount(BigDecimal.valueOf(lossCount));
                detail.setStockDetailId(stockDetail.getId());
                detail.setWastageBillId(bill.getId());
                wastageBillDetailMapper.insert(detail);
                journalMapper.insert(createJournal(ex, stockDetail.getId(), null));
                return 0d;
            } catch (Exception e) {
                throw e;
            }
        }

        private Double greaterThanLossCountHandler(ExtinguishantOnCar ex, Double lossCount) throws Exception {
            try {
                StockDetail stockDetail = getDetailById(ex.getStockDetailId());
                if (stockDetail == null) {
                    return 0d;
                }
                stockDetail.setAmount(stockDetail.getAmount() - lossCount);
                stockDetailMapper.updateById(stockDetail);
                addStockDetailId(stockDetail.getId());

                StockDetail stockDetail_clone = stockDetail.clone();
                stockDetail_clone.setId(null);
                stockDetail_clone.setAmount(lossCount);
                stockDetail_clone.setStatus(EquipStatusEnum.LOSS.getCode().toString());
                stockDetailMapper.insert(stockDetail_clone);
                addStockDetailId(stockDetail_clone.getId());
                Stock stock = stockMapper.selectById(stockDetail.getStockId());
                stock.setAmount(stock.getAmount() - lossCount);
                stockMapper.updateById(stock);
                ex.setAmount(ex.getAmount() - lossCount);
                extinguishantOnCarMapper.updateById(ex);

                // 损耗清单详情
                WastageBillDetail detail = new WastageBillDetail();
                detail.setAmount(BigDecimal.valueOf(lossCount));
                detail.setStockDetailId(stockDetail_clone.getId());
                detail.setWastageBillId(bill.getId());
                wastageBillDetailMapper.insert(detail);
                journalMapper.insert(createJournal(ex, stockDetail_clone.getId(), lossCount));
                return 0d;
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
        }

        public Journal createJournal(ExtinguishantOnCar e, Long stockDetailId, Double amount) {
            Journal journal = new Journal();
            Double lossAmount = (null != amount) ? amount : e.getAmount();
            Long lossStockDetailId = (null != stockDetailId) ? stockDetailId : e.getStockDetailId();
            journal.setAmount(lossAmount);
            journal.setCarId(getCarId());
            journal.setEquipmentDetailId(e.getEquipmentDetailId());
            journal.setUserId(Long.valueOf(getUser().getUserId()));
            // 查询EquipmentDetail
            EquipmentDetail equipmentDetail = equipmentDetailMapper
                    .selectById(getDetailById(e.getStockDetailId()).getEquipmentDetailId());
            Equipment equipment = iEquipmentService.getById(equipmentDetail.getEquipmentId());
            Unit unit = unitMapper.selectById(equipment.getUnitId());
            journal.setRemark(String.format("【%s】在车牌号为【%s】的车辆上，损耗了【%.2f】%s【%s】", getUser().getRealName(),
                    getCar().getCarNum(), lossAmount, unit.getName(), equipmentDetail.getName()));
            journal.setOrgCode(getCar().getOrgCode());
            journal.setStockDetailId(lossStockDetailId);
            journal.setState(getLossStateId().toString());

            return journal;
        }

        public Set<Long> getStockDetailIds() {
            return stockDetailIds;
        }

        public void setStockDetailIds(Set<Long> stockDetailIds) {
            this.stockDetailIds = stockDetailIds;
        }

        public void addStockDetailId(Long id) {
            stockDetailIds.add(id);
        }

        public Long getLossStateId() {
            return lossStateId;
        }

        public void setLossStateId(Long lossStateId) {
            this.lossStateId = lossStateId;
        }
    }

    @PostConstruct
    public void init() {
        if (null == loadingHandlers) {
            loadingHandlers = new ArrayList<Consumer<LoadingParams>>();

            loadingHandlers.add((p) -> {
                p.setCar(carMapper.selectById(p.getCarId()));

                List<Long> stockDetailIds = p.getExtinguishants().stream().map(ExtinguishantRequeset::getStockDetailId)
                        .collect(Collectors.toList());

                Map<Long, StockDetail> details = new HashMap<>();
                stockDetailMapper.findByIdInAndStatus(stockDetailIds, EquipStatusEnum.REPERTORY.getCode())
                        .forEach(s -> details.put(s.getId(), s));

                p.setDetails(details);

                Map<String, Object> columnMap = new HashMap<String, Object>();
                columnMap.put("type", "JournalType");
                columnMap.put("code", JournalTypeEnum.CZ.getCode());
                List<SystemDic> listd = systemDicMapper.selectByMap(columnMap);
                p.setLoadingId(listd.get(0).getCode());
            });

            loadingHandlers.add(this::destocking);

//			loadingHandlers.add((p) -> 
//				AsynUtils.run(p.getStockDetailIds(), iRemoteSearchServer::updateStockDetails));
        }
        if (null == lossHandlers) {
            lossHandlers = new ArrayList<Consumer<LossParams>>();
            lossHandlers.add(p -> {
                p.setCar(carMapper.selectById(p.getCarId()));
                Map<String, Object> columnMap = new HashMap<String, Object>();
                columnMap.put("car_id", p.getCarId());
                List<ExtinguishantOnCar> extinguishantOnCar = extinguishantOnCarMapper.selectByMap(columnMap);
                p.setExtinguishantOnCar(extinguishantOnCar);
                List<Long> stockDetailIds = p.getExtinguishantOnCar().stream().map(ExtinguishantOnCar::getStockDetailId)
                        .collect(Collectors.toList());
                Map<Long, StockDetail> details = new HashMap<>();
                stockDetailMapper.findByIdInAndStatus(stockDetailIds, EquipStatusEnum.ONCAR.getCode())
                        .forEach(s -> details.put(s.getId(), s));
                p.setDetails(details);
                columnMap.clear();
                columnMap.put("type", "JournalType");
                columnMap.put("code", JournalTypeEnum.SH.getCode());
                List<SystemDic> listd = systemDicMapper.selectByMap(columnMap);
                p.setLossStateId(listd.get(0).getId());
            });
            lossHandlers.add(p -> this.loss(p));

            // 同步搜索
            /*
             * lossHandlers.add((p) -> AsynUtils.run(p.getStockDetailIds(),
             * iRemoteSearchServer::updateStockDetails));
             */
        }
    }

    @Transactional(rollbackFor = RuntimeException.class)
    void destocking(LoadingParams params) {
        try {
            params.getExtinguishants().forEach(r -> {
                // 去库存
                StockDetail detail = params.getDetailById(r.getStockDetailId());
                detail.setAmount(detail.getAmount() - r.getAmount());
                stockDetailMapper.updateById(detail);
                params.addStockDetailId(r.getStockDetailId());

                StockDetail detail_onCar = null;

                // 新增车载记录
                detail_onCar = detail.clone();
                detail_onCar.setId(null);
                detail_onCar.setAmount(r.getAmount());
                detail_onCar.setStatus(EquipStatusEnum.ONCAR.getCode().toString());
                stockDetailMapper.insert(detail_onCar);
                params.addStockDetailId(detail_onCar.getId());

                // 装车
                extinguishantOnCarMapper.insert(params.create(r, detail_onCar));

                // 流水
                journalMapper.insert(params.createJournal(r, detail_onCar.getId()));

            });
        } catch (Exception e) {
            throw new RuntimeException("系统异常！");
        }
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void loss(Object o) {
        LossParams params = (LossParams) o;
        // 生成损耗单
        WastageBill bill = new WastageBill();
        // 生成损耗单据编号
        List<Map<String, Object>> wastage = wastageBillMapper.getOneByIdDesc();
        String billCode = "";
        if (null == wastage || wastage.size() < 1) {
            billCode = getCurrentPrefix() + "0001";
        } else {
            String str = (wastage.get(0).get("bill_code")).toString().substring(2);
            Long value = Long.valueOf(str) + 1L;
            billCode = BillCodeManagerUtil.LOSS + value.toString();
        }
        String code2 = BillCodeManagerUtil.checkCoding(BillCodeManagerUtil.LOSS, billCode);
        bill.setBillCode(code2);
        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("type", "StockBillType");
        columnMap.put("code", StockBillTypeEnum.SHCK.getValue());
        List<SystemDic> listd = systemDicMapper.selectByMap(columnMap);
        bill.setBillType(StockBillTypeEnum.SHCK.getValue());
        bill.setCreatorId(Long.valueOf(getUser().getUserId()));
        bill.setCreatorName(getUser().getRealName());
        bill.setOrgCode("");
        // bill.setOrgCode(user.getCompany().getCompCode());
        wastageBillMapper.insert(bill);
        wastageBillMapper.updateById(bill);
        params.setBill(bill);

        params.getExtinguishants().forEach(r -> {
            try {
                // 减车载
                Double lossCount = r.getTotal() - r.getAmount();
                if (0 >= lossCount) {
                    throw new IllegalArgumentException("消耗量不能为0或者小于0！");
                }
                List<ExtinguishantOnCar> list = ArrayUtil.filter(params.getExtinguishantOnCar(),
                        e -> e.getEquipmentDetailId().longValue() == r.getEquipmentDetailId().longValue());
                for (ExtinguishantOnCar e : list) {

                    // 车载记录总和 大于等于 消耗量
                    if (r.getTotal().doubleValue() == lossCount.doubleValue()) {
                        lossCount = params.equalLossCountHandler(e, lossCount);
                        break;
                    } else if (r.getTotal().doubleValue() > lossCount.doubleValue()) {

                        lossCount = params.greaterThanLossCountHandler(e, lossCount);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("系统异常！");
            }
        });
    }

    /**
     * 获取单据编码前缀
     *
     * @return
     */
    private String getCurrentPrefix() {
        return BillCodeManagerUtil.LOSS + DateUtils.get(Calendar.YEAR) + DateUtils.get(Calendar.MONTH)
                + DateUtils.get(Calendar.DAY_OF_MONTH);
    }

    @Override
    public Map<String, String> loadingExtinguishants(Long carId, List<ExtinguishantRequeset> extinguishants) {
        Car car = this.getById(carId);
        if (car.getCarState().equals(CarStatusEnum.WX.getCode()) || car.getCarState().equals(CarStatusEnum.BF.getCode())) {
            throw new RuntimeException("报废维修车辆不能装载");
        }
        LoadingParams params = new LoadingParams(carId, extinguishants);
        loadingHandlers.forEach(handler -> handler.accept(params));
        Map<String, String> result = new HashMap<>();
        result.put("person", getUser().getRealName());
        result.put("time", DateUtils.getNowStrLong());
        result.put("number", null);
        return result;
    }

    class LoadingParams {
        private Long carId;

        private String loadingId;

        private List<ExtinguishantRequeset> extinguishants;

        private Car car;

        private Map<Long, StockDetail> details;

        private Set<Long> stockDetailIds;

        public LoadingParams(Long carId, List<ExtinguishantRequeset> extinguishants) {
            this.carId = carId;
            this.extinguishants = extinguishants;
            setStockDetailIds(new HashSet<>());
        }

        public ExtinguishantOnCar create(ExtinguishantRequeset r, StockDetail detail) {
            ExtinguishantOnCar extinguishantOnCar = new ExtinguishantOnCar();
            extinguishantOnCar.setCarId(carId);
            extinguishantOnCar.setAmount(r.getAmount());
            extinguishantOnCar.setStockDetailId(detail.getId());
            extinguishantOnCar.setEquipmentDetailId(getDetailById(r.getStockDetailId()).getEquipmentDetailId());
            return extinguishantOnCar;
        }

        public Journal createJournal(ExtinguishantRequeset r, Long stockDetailId) {
            // 查询EquipmentDetail
            EquipmentDetail equipmentDetail = equipmentDetailMapper
                    .selectById(getDetailById(r.getStockDetailId()).getEquipmentDetailId());
            Equipment equipment = iEquipmentService.getById(equipmentDetail.getEquipmentId());
            Unit unit = unitMapper.selectById(equipment.getUnitId());
            Journal journal = new Journal();
            journal.setAmount(r.getAmount());
            journal.setCarId(getCarId());
            journal.setEquipmentDetailId(getDetailById(r.getStockDetailId()).getEquipmentDetailId());
            journal.setUserId(Long.valueOf(getUser().getUserId()));
            journal.setWarehouseStructureId(getDetailById(r.getStockDetailId()).getWarehouseStructureId());

            journal.setRemark(String.format("【%s】向车牌号为【%s】的车辆上，装载了【%.2f】%s【%s】", getUser().getRealName(),
                    getCar().getCarNum(), r.getAmount(), unit.getName(), equipmentDetail.getName()));
            journal.setOrgCode(getCar().getOrgCode());
            journal.setStockDetailId(stockDetailId);
            journal.setState(getLoadingId());

            return journal;
        }

        public StockDetail getDetailById(Long id) {
            return details.get(id);
        }

        public Long getCarId() {
            return carId;
        }

        public void setCarId(Long carId) {
            this.carId = carId;
        }

        public List<ExtinguishantRequeset> getExtinguishants() {
            return extinguishants;
        }

        public void setExtinguishants(List<ExtinguishantRequeset> extinguishants) {
            this.extinguishants = extinguishants;
        }

        public Car getCar() {
            return car;
        }

        public void setCar(Car car) {
            this.car = car;
        }

        public Map<Long, StockDetail> getDetails() {
            return details;
        }

        public void setDetails(Map<Long, StockDetail> details) {
            this.details = details;
        }

        public Set<Long> getStockDetailIds() {
            return stockDetailIds;
        }

        public void setStockDetailIds(Set<Long> stockDetailIds) {
            this.stockDetailIds = stockDetailIds;
        }

        public void addStockDetailId(Long id) {
            stockDetailIds.add(id);
        }

        public String getLoadingId() {
            return loadingId;
        }

        public void setLoadingId(String loadingId) {
            this.loadingId = loadingId;
        }
    }

    @Override
    public void loadingEquipment(OnBoardEquipment equipment, AgencyUserModel user) {
        List<Equip> eqs = generate(equipment);
        try {
            eqs.forEach(eq -> {
                StockDetail detail = getEligibleStockDetail(eq);
                if (null == detail) {
                    throw new RuntimeException("二维码为【" + eq.getQrCode() + "】的装备库存量不足！");
                }
                updateStockDetail(detail, equipment.getType(), null, null);
                loading(detail, eq);
                generateJournal(detail, eq, equipment.getType(), user, null);
            });
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

    }

    private void loading(StockDetail detail, Equip eq) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("qr_code", detail.getQrCode());
        EquipmentSpecific equipmentSpecific = equipmentSpecificMapper.selectOne(queryWrapper);
        EquipmentOnCar equipmentOnCar = new EquipmentOnCar();
        equipmentOnCar.setCarId(eq.getCarId());
        equipmentOnCar.setStockDetailId(detail.getId());
        equipmentOnCar.setAmount(eq.getAmount());
        equipmentOnCar.setEquipmentDetailId(eq.getEquipmentDetailId());
        if (equipmentSpecific != null) {
            equipmentOnCar.setEquipmentSpecificId(equipmentSpecific.getId());
        }
        equipmentOnCarMapper.insert(equipmentOnCar);
    }

    private void generateJournal(StockDetail detail, Equip eq, String type, AgencyUserModel user, Long shelfCellId) {
        OnBoardEquipmentEnum typeEnum = OnBoardEquipmentEnum.getEnum(type);
        Journal journal = new Journal();
        journal.setUserId(Long.valueOf(user.getUserId()));
        journal.setEquipmentDetailId(eq.getEquipmentDetailId());
        journal.setAmount(eq.getAmount());
        journal.setOrgCode(getSelectedOrgInfo().getCompany().getOrgCode());
        journal.setStockDetailId(detail.getId());

        Car car = carMapper.selectById(eq.getCarId());
        if (null == car) {
            throw new RuntimeException("车辆不存在！");
        }
        EquipmentDetail equipmentDetail = equipmentDetailMapper.selectById(eq.getEquipmentDetailId());
        if (typeEnum == OnBoardEquipmentEnum.LOAD) {

            // 查询装备状态
            Map<String, Object> columnMap = new HashMap<String, Object>();
            columnMap.put("type", "JournalType");
            columnMap.put("code", JournalTypeEnum.CZ.getCode());
            List<SystemDic> list = systemDicMapper.selectByMap(columnMap);
            ParsePropertyUtil.setting(journal::setState, () -> list.get(0).getId().toString());

            journal.setRemark(user.getRealName() + "将" + equipmentDetail.getName() + "装备装载到车牌号为【" + car.getCarNum() + "】的车辆上。");
            journal.setWarehouseStructureId(detail.getWarehouseStructureId());
            journal.setCarId(eq.getCarId());
        } else if (typeEnum == OnBoardEquipmentEnum.UNLOAD) {
            journal.setRemark(user.getRealName() + "从车牌号为【" + car.getCarNum() + "】的车辆上卸载了" + equipmentDetail.getName() + "装备。");
            journal.setWarehouseStructureId(shelfCellId);
            journal.setCarId(eq.getCarId());
        }
        journalMapper.insert(journal);
    }

    private List<Equip> generate(OnBoardEquipment equipment) {
        return equipment.getEquipments().parallelStream().map(eq -> {
            eq.setWarehouseId(equipment.getWarehouseId());
            return eq;
        }).collect(Collectors.toList());
    }

    private StockDetail getEligibleStockDetail(Equip eq) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("qr_code", eq.getQrCode());
        queryWrapper.eq("warehouse_id", eq.getWarehouseId());
        queryWrapper.gt("amount", 0d);
        List<StockDetail> details = stockDetailMapper.selectList(queryWrapper);

        return details.isEmpty() ? null : details.get(0);
    }

    private void updateStock(StockDetail detail, double amount) {
        Stock stock = stockMapper.selectById(detail.getStockId());
        stock.setAmount(stock.getAmount() + amount);
        stockMapper.updateById(stock);
    }

    private Stock changeStock(Long warehouseId, Long equipmentDetailId, String orgCode) {
        // Stock stock =
        // iStockDao.findByEquipmentDetailIdAndWarehouseId(equipmentDetailId,
        // warehouseId);
        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("equipment_detail_id", equipmentDetailId);
        columnMap.put("warehouse_id", warehouseId);
        List<Stock> stock = stockMapper.selectByMap(columnMap);
        Stock stock1 = new Stock();
        if (null == stock && stock.size() > 0) {
            stock1.setAmount(0d);
            stock1.setEquipmentDetailId(equipmentDetailId);
            stock1.setWarehouseId(warehouseId);
            stock1.setOrgCode(orgCode);
            stockMapper.insert(stock1);
        }
        return stock1;
    }

    private void updateStockDetail(StockDetail detail, String type, Long warehouseId, Long shelfCellId) {
        OnBoardEquipmentEnum typeEnum = OnBoardEquipmentEnum.getEnum(type);
        if (typeEnum == OnBoardEquipmentEnum.LOAD) {
            //TODO 更新为自己去反，之前为减去1，这样在设备管理方式为批量管理时，就不对了
            updateStock(detail, detail.getAmount() * -1);
            detail.setAmount(0.0);
            detail.setStatus(EquipStatusEnum.ONCAR.getCode().toString());
        } else if (typeEnum == OnBoardEquipmentEnum.UNLOAD) {
            if (null != shelfCellId) {
                // 更换仓库id，就需要更换该stockDetail对应的stock
                if (warehouseId != null && warehouseId.longValue() != detail.getWarehouseId()) {
                    Stock stock = changeStock(warehouseId, detail.getEquipmentDetailId(), detail.getOrgCode());
                    detail.setStockId(stock.getId());
                }
                detail.setWarehouseId(warehouseId);
                detail.setWarehouseStructureId(shelfCellId);
            }
            detail.setStatus(EquipStatusEnum.REPERTORY.getCode().toString());
            //卸载将卸载的数量恢复
            updateStock(detail, detail.getAmount());
        }
        stockDetailMapper.updateById(detail);
    }

    @Override
    public void unloadEquipment(OnBoardEquipment equipment, AgencyUserModel user) {
        List<Equip> eqs = generate(equipment);
        String area = equipment.getArea();
        //TODO: 是否返回原始位置：true-是 false -否 ，equipment.getShelfCellCode() 为空或者为null，代表，装备的卸载是，放回原位
        boolean isOriPosition = StringUtil.isEmpty(equipment.getShelfCellCode());
        //新存放的货位id,不放回原位使用
        Long shelfCellId = null;
        //TODO: 不放回原位，查询存放位置(正常逻辑，应该是前端返回操作类型及货位id,后端不需要进行查询)
        if (!isOriPosition && equipment.getWarehouseId() != null) {
            shelfCellId = queryShelfCellId(equipment);
        }
        try {
            Long finalShelfCellId = shelfCellId;
            eqs.forEach(eq -> {
                EquipmentOnCar equipmentOnCar = checkEquipment(eq);
                if (null == equipmentOnCar) {
                    throw new RuntimeException("二维码为【" + eq.getQrCode() + "】的装备未装备在车上，不用卸载!");
                }
                StockDetail detail = stockDetailMapper.selectById(equipmentOnCar.getStockDetailId());
                if (null == detail) {
                    throw new RuntimeException("二维码为【" + eq.getQrCode() + "】的装备未记录在库!");
                }
                //卸载将转载的数量回复回去
                if (finalShelfCellId != null) {
                    iEquipmentDetailService.update(new UpdateWrapper<EquipmentDetail>().eq("id", eq.getEquipmentDetailId()).set("area", area));
                }
                detail.setAmount(equipmentOnCar.getAmount());
                unLoad(equipmentOnCar);
                updateStockDetail(detail, equipment.getType(), equipment.getWarehouseId(), finalShelfCellId);
                generateJournal(detail, eq, equipment.getType(), user, finalShelfCellId);
            });
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

    }

    private void unLoad(EquipmentOnCar equipmentOnCar) {
        equipmentOnCarMapper.deleteById(equipmentOnCar.getId());

    }

    private EquipmentOnCar checkEquipment(Equip eq) {

        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("qr_code", eq.getQrCode());
        List<EquipmentOnCar> list2 = null;
        List<StockDetail> list = stockDetailMapper.selectByMap(columnMap);
        if (list != null && list.size() > 0) {
            columnMap.clear();
            columnMap.put("equipment_detail_id", eq.getEquipmentDetailId());
            columnMap.put("car_id", eq.getCarId());
            columnMap.put("stock_detail_id", list.get(0).getId());
            list2 = equipmentOnCarMapper.selectByMap(columnMap);
        }
        if (list2 != null && list2.size() > 0) {
            return list2.get(0);
        }
        return null;
    }

    private Long queryShelfCellId(OnBoardEquipment equipment) {
        //存放到其他位置
        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("warehouse_id", equipment.getWarehouseId());
        columnMap.put("code", equipment.getShelfCellCode());
        List<WarehouseStructure> shelfCell = warehouseStructureMapper.selectByMap(columnMap);
        if (shelfCell.isEmpty()) {
            throw new RuntimeException("货位信息获取失败!");
        }
        return shelfCell.get(0).getId();

    }

    @Override
    public IPage<Car> getCarList(String ercode, String orgcode, Car car, Page<Car> pageBean) {
        QueryWrapper<Car> queryWrapper = new QueryWrapper<>();
        List<Equipment> equipmentList = iEquipmentService.list(new QueryWrapper<Equipment>().likeRight("code", ercode));
        List<Long> idList = new ArrayList<Long>();
        for (Equipment equipment : equipmentList) {
            idList.add(equipment.getId());
        }
        if (!StringUtil.isEmpty(car.getStandard())) {
            queryWrapper.eq("standard", car.getStandard());
        }
        if (car.getCarState() != null) {
            queryWrapper.eq("car_state_id", car.getCarState());
        }
        if (!StringUtil.isEmpty(car.getBrand())) {
            queryWrapper.eq("brand", car.getBrand());
        }
        if (!StringUtil.isEmpty(orgcode)) {
            queryWrapper.eq("org_code", orgcode);
        }
        if (idList != null) {
            queryWrapper.in("equipment_id", idList);
        }
        IPage<Car> page = this.page(pageBean, queryWrapper);
        for (Car carOne : page.getRecords()) {
            Equipment equipment = iEquipmentService.getById(carOne.getEquipmentId());
            String utilName = carMapper.getUtilName(equipment.getUnitId());
            carOne.setUnitName(utilName);
            equipment.setImg(fileServer + equipment.getImg());
            carOne.setEquipment(equipment);
            carOne.setCarState(CarStatusEnum.getEnum(carOne.getCarState().toString()).getName());
        }
        return page;
    }

    @Override
    public Car saveOne(Car car) {
        //如果没有状态默认状态在位
        if (StringUtils.isEmpty(car.getCarState())) {
            car.setCarState(CarStatusEnum.ZW.getCode());
        }
        String orgCode = remoteSecurityService.getAgencyUser().getCompanys().get(0).getOrgCode();
        car.setOrgCode(orgCode);
        boolean save = this.save(car);
        //  AST数据同步
        if (save && syncSwitch) {
            FireVehicle fireVehicle = getFireVehicleDetailById(car.getId());
            syncDataService.syncCreatedFireVehicle(fireVehicle);
        }
        List<CarProperty> carPropertyList = car.getCarPropertyList();
        if (carPropertyList != null) {
            for (CarProperty carProperty : carPropertyList) {
                carProperty.setCarId(car.getId());
            }
            boolean saveBatch = iCarPropertyService.saveBatch(carPropertyList);
            //  AST数据同步
            if (saveBatch && syncSwitch) {
                dataSyncSaveOrUpdate(car);
            }
        }
        List<UploadFile> fileList = new ArrayList<UploadFile>();
        fileList.addAll(fillFileList(car.getImg(), car.getId(), FileTypeEnum.image.toString()));
        fileList.addAll(fillFileList(car.getVideo(), car.getId(), FileTypeEnum.video.toString()));
        fileList.addAll(fillFileList(car.getCertification(), car.getId(), FileTypeEnum.certificate.toString()));
        fileList.addAll(fillFileList(car.getInstruction(), car.getId(), FileTypeEnum.instruction.toString()));
        iUploadFileService.saveBatch(fileList);
        syncDataService.saveOrUpdateEquipIotCodeRedisData(null);
        return car;
    }

    @Override
    @Async
    public FireVehicle getFireVehicleDetailById(Long id) {
        return carMapper.getFireVehicleDetailById(id);
    }

    @Override
    public List<CarInfoDto> carInfoList(Long teamId, String name) {
        LambdaQueryWrapper<Car> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(teamId != null, Car::getTeamId, teamId);
        wrapper.like(!StringUtil.isEmpty(name), Car::getName, name);
        wrapper.in(Car::getCarState,"1","2");
        wrapper.orderByDesc(BaseEntity::getCreateDate);
        List<Car> carList = this.list(wrapper);
        List<Equipment> equipmentList = iEquipmentService.list();
        /*统一车辆图片使用装备定义图片 2021-10-27 陈召*/
        equipmentList.stream().filter(e->e.getName().contains("车")).forEach(e->{
            carList.forEach(car->{
                if (e.getId().equals(car.getEquipmentId())){
                    List<UploadFile>  objects = new ArrayList<>();
                    UploadFile uploadFile = new UploadFile();
                    uploadFile.setUrl(e.getImg());
                    objects.add(uploadFile);
                    car.setImg(objects);
                }
            });
        });
        /*统一车辆图片使用装备定义图片 2021-10-27 陈召*/
        Map<Long, Equipment> keyMap = equipmentList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        List<EquipmentCategory> categoryList = iEquipmentCategoryService.list();
        Map<Long, String> categoryMap = categoryList.stream().collect(Collectors.toMap(BaseEntity::getId, EquipmentCategory::getName));
        List<UploadFile> fileList = iUploadFileService.list(new LambdaQueryWrapper<UploadFile>()
                .eq(UploadFile::getObjectType, "car")
                .eq(UploadFile::getFileType, "image"));

        // 车载装备
        List<Map<String, Object>> carResourceMapList = this.baseMapper.getCarResourceMapList(null);
        Map<String, List<Map<String, Object>>> carResourceMap =
                carResourceMapList.stream().collect(Collectors.groupingBy(car -> car.get("carId").toString()));
        return carList.stream().map(car -> {
            CarInfoDto carInfoVo = new CarInfoDto();
            Bean.copyExistPropertis(car, carInfoVo);
            Equipment equipment = keyMap.get(carInfoVo.getEquipmentId());
            carInfoVo.setCarStateDesc(this.getCarStateDesc(car));
            carInfoVo.setEquipmentName(equipment != null ? equipment.getName() : "");
            carInfoVo.setCategoryId(equipment != null ? equipment.getCategoryId() : null);
            carInfoVo.setCategoryName(categoryMap.get(carInfoVo.getCategoryId()));
            if (car.getImg() != null){
                List<String> img = new ArrayList<>();
                img.add(car.getImg().get(0).getUrl());
                carInfoVo.setImage(img);
            }
            carInfoVo.setResourceList(carResourceMap.get(car.getId().toString()));
            return carInfoVo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Map<String, Object>> teamCarList() {
        return this.baseMapper.getCarNumGroupByTeamId();
    }

    private String getCarStateDesc(Car car) {
        CarStatusEnum carStatusEnum = CarStatusEnum.getEnum(car.getCarState());
        if (carStatusEnum != null) {
            return carStatusEnum.getName();
        }
        return "";
    }

    @Async
    void dataSyncSaveOrUpdate(Car car) {
        CarIndexVo carIndexVo = new CarIndexVo();
        carIndexVo.setId(car.getId());
        List<CarPropertyVo> propertyList = carPropertyService.getCarPropertyList(carIndexVo);
        List<CarPropertyVo> fireVehicleInfoList = propertyList.stream().filter(propertyVo -> 0 == propertyVo.getIsIot()).collect(Collectors.toList());
        List<CarPropertyVo> fireVehicleMeasurementList = propertyList.stream().filter(propertyVo -> propertyVo.getIsIot() != null && 1 == propertyVo.getIsIot()).collect(Collectors.toList());
        syncDataService.syncCreatedFireVehicleInfo(fireVehicleInfoList);
        syncDataService.syncCreatedFireVehicleMeasurement(fireVehicleMeasurementList);
    }

    @Override
    public void dataSyncDeletedIds(List<Long> carIds) {
        List<CarPropertyVo> propertyList = carPropertyService.getCarPropertyListByCarIds(carIds);
        List<Long> fireVehicleInfoList = propertyList.stream().filter(propertyVo -> 0 == propertyVo.getIsIot()).map(CarPropertyVo::getId).collect(Collectors.toList());
        List<Long> fireVehicleMeasurementList = propertyList.stream().filter(propertyVo -> propertyVo.getIsIot() != null && 1 == propertyVo.getIsIot()).map(CarPropertyVo::getId).collect(Collectors.toList());
        syncDataService.syncDeletedFireVehicleInfo(fireVehicleInfoList);
        syncDataService.syncDeletedFireVehicleMeasurement(fireVehicleMeasurementList);
    }

    private List<UploadFile> fillFileList(List<UploadFile> list, Long id, String type) {
        if (list == null) {
            return new ArrayList<UploadFile>();
        }
        list.forEach(item -> {
            if (item.getUrl().contains(fileServer)) {
                item.setUrl(item.getUrl().replace(fileServer, ""));
            }
            item.setFileType(type);
            item.setObjectType(BillContentEnum.CL.getKey());
            item.setObjectId(id);
        });
        return list;
    }

    @Override
    public Car updateOneById(Car car) {
        String orgCode = remoteSecurityService.getAgencyUser().getCompanys().get(0).getOrgCode();
        car.setOrgCode(orgCode);
        // @TableField(updateStrategy = FieldStrategy.IGNORED) 置空不生效 为空单独设置 by kongfm 2021-09-09
        this.update(new LambdaUpdateWrapper<Car>().set(Car::getAgencyId,car.getAgencyId() ).set(Car::getTeamId,car.getTeamId()).eq(Car::getId,car.getId()));
        boolean update = this.updateById(car);
        //  AST数据同步
        if (update && syncSwitch) {
            FireVehicle fireVehicle = getFireVehicleDetailById(car.getId());
            syncDataService.syncCreatedFireVehicle(fireVehicle);
        }
        List<CarProperty> carPropertyList = car.getCarPropertyList();
        if (carPropertyList.size() > 0) {
            carPropertyList.forEach(x -> {
                if ("state".equals(x.getNameKey())) {
                    if ("是".equals(x.getValue())) {
                        x.setValue(TrueOrFalseEnum.real.value);
                    } else {
                        x.setValue(TrueOrFalseEnum.fake.value);
                    }
                }
            });
            carPropertyList.forEach(x -> x.setCarId(car.getId()));
            iCarPropertyService.remove(new QueryWrapper<CarProperty>().lambda().eq(CarProperty::getCarId, car.getId()));
            boolean saveBatch = iCarPropertyService.saveBatch(carPropertyList);
            //  AST数据同步
            if (saveBatch && syncSwitch) {
                dataSyncSaveOrUpdate(car);
            }
        }
        iUploadFileService.remove(new QueryWrapper<UploadFile>().eq("object_type", BillContentEnum.CL.getKey())
                .eq("object_id", car.getId()));
        List<UploadFile> fileList = new ArrayList<UploadFile>();
        fileList.addAll(fillFileList(car.getImg(), car.getId(), FileTypeEnum.image.toString()));
        fileList.addAll(fillFileList(car.getVideo(), car.getId(), FileTypeEnum.video.toString()));
        fileList.addAll(fillFileList(car.getCertification(), car.getId(), FileTypeEnum.certificate.toString()));
        fileList.addAll(fillFileList(car.getInstruction(), car.getId(), FileTypeEnum.instruction.toString()));
        iUploadFileService.saveBatch(fileList);
        syncDataService.saveOrUpdateEquipIotCodeRedisData(null);
        return car;
    }

    @Override
    public Car selectOneById(Long id) {
        Car car = this.getById(id);
        car.setQrCode("03#" + car.getQrCode());
        List<CarProperty> carPropertyList = iCarPropertyService.list(new QueryWrapper<CarProperty>().eq("car_id", id));
        for (CarProperty carProperty : carPropertyList) {
            EquipmentIndex perfQuota = equipmentIndexService.getById(carProperty.getEquipmentIndexId());
            if (perfQuota != null) {
                carProperty.setPerfQuotaName(perfQuota.getPerfQuotaName());
                carProperty.setGroupName(perfQuota.getGroupName());
                carProperty.setUnitName(perfQuota.getUnitName());
                carProperty.setNameKey(perfQuota.getPerfQuotaDefinitionId());
            }
        }
        carPropertyList.forEach(x -> {
            if ("state".equals(x.getNameKey())) {
                if (TrueOrFalseEnum.real.value.equals(x.getValue())) {
                    x.setValue("是");
                } else {
                    x.setValue("否");
                }
            }
            if ("labels".equals(x.getNameKey())) {
                List<String> newLabels = new ArrayList();
                String eqList = x.getValue();
                if (StringUtil.isNotEmpty(eqList)) {
                    String regex = "[\\[\\]]";
                    eqList = eqList.replaceAll(regex, "").replaceAll("\"", "");
                    String strings[] = eqList.split(",");
                    List<String> list = Arrays.asList(strings);
                    for (String str : list) {
                        EquipmentSpecificVo equipmentSpecific = equipmentSpecificMapper.getEquipmentNameByIotCode(str);
                        if (null != equipmentSpecific) {
                            newLabels.add(equipmentSpecific.getName());
                        }
                    }
                    String newLabelValue = "";
                    if (newLabels.size() > 0) {
                        newLabelValue = newLabels.toString().replaceAll(regex, "");
                    }
                    x.setValue(newLabelValue);
                }
            }
            if (!StringUtil.isNotEmpty(x.getGroupName())) {
                x.setGroupName("其他");
            }
        });
        car.setCarPropertyList(carPropertyList);

        ManufacturerInfo manufacturerInfo = iManufacturerInfoService.getById(car.getManufacturerId());
        manufacturerInfo.setImg(fileServer + manufacturerInfo.getImg());
        car.setManufacturerInfo(manufacturerInfo);
        car.setImg(getCarFileList(id, FileTypeEnum.image.toString()));
        car.setVideo(getCarFileList(id, FileTypeEnum.video.toString()));
        car.setCertification(getCarFileList(id, FileTypeEnum.certificate.toString()));
        car.setInstruction(getCarFileList(id, FileTypeEnum.instruction.toString()));
        Equipment equipment = iEquipmentService.getById(car.getEquipmentId());
        if (!ObjectUtils.isEmpty(equipment.getCategoryId())) {
            equipment.setEquipmentCategory(equipmentCategoryMapper.selectById(equipment.getCategoryId()));
        }
        car.setEquipment(equipment);
        car.setCountryName(iSystemDicService.getOne(new QueryWrapper<SystemDic>().eq("id", car.getCountry())).getName());
        car.setChassisCountryName(
                iSystemDicService.getOne(new QueryWrapper<SystemDic>().eq("id", car.getChassisCountry())).getName());
        car.setJournals(journalService.list(new QueryWrapper<Journal>().eq("car_id", car.getId()).orderByAsc("create_date")));
        car.setEquipmentsOnCar(this.baseMapper.selectEquipmentOnCarAppList(car.getId()));
        List<Equipment> equipment1 = iEquipmentService.listByCategoryId(equipment.getCategoryId());
        car.setUnit(equipment1.get(0).getUnit());
        return car;
    }

    @Override
    public Car getCarDetailById(Long id) {
        Car car = this.getById(id);
        if (car != null) {
            List<CarIndexVo> carVoList = this.baseMapper.getCarIndexs(id);
            Map<String, List<CarIndexVo>> map = carVoList.stream().collect(Collectors.groupingBy(vo -> vo.getName()));
            car.setExt(JSONObject.toJSONString(map));
            ManufacturerInfo manufacturerInfo = iManufacturerInfoService.getById(car.getManufacturerId());
            manufacturerInfo.setImg(fileServer + manufacturerInfo.getImg());
            car.setManufacturerInfo(manufacturerInfo);
            car.setImg(getCarFileList(id, FileTypeEnum.image.toString()));
            Equipment equipment = iEquipmentService.getById(car.getEquipmentId());
            if (!ObjectUtils.isEmpty(equipment.getCategoryId())) {
                equipment.setEquipmentCategory(equipmentCategoryMapper.selectById(equipment.getCategoryId()));
            }
            car.setCarState(CarStatusEnum.getNameByCode(car.getCarState()));
            car.setCountry(iSystemDicService.getByIdforAll(Long.valueOf(car.getCountry())).getName());
            car.setUnitName(iUnitService.getById(equipment.getUnitId()).getName());
            car.setEquipment(equipment);
            car.setFullQrCode("03#" + car.getQrCode());
        }
        return car;
    }

    @Override
    public Car getCarDetailByCarNum(String carNum, String orgCode) {
        QueryWrapper<Car> carQueryWrapper = new QueryWrapper<>();
        carQueryWrapper.eq("car_num", carNum);
        Car car = carMapper.selectOne(carQueryWrapper);

        List<CarIndexVo> carVoList = getCarsInfoByOrgCode(orgCode);
        List<CarProperty> propertyList = new ArrayList<>();
        Map<String, List<CarIndexVo>> map = carVoList.stream().collect(Collectors.groupingBy(vo -> vo.getName()));
        car.setExt(JSONObject.toJSONString(map));
        ManufacturerInfo manufacturerInfo = iManufacturerInfoService.getById(car.getManufacturerId());
        manufacturerInfo.setImg(fileServer + manufacturerInfo.getImg());
        car.setManufacturerInfo(manufacturerInfo);
        car.setImg(getCarFileList(car.getId(), FileTypeEnum.image.toString()));
        Equipment equipment = iEquipmentService.getById(car.getEquipmentId());
        if (!ObjectUtils.isEmpty(equipment.getCategoryId())) {
            equipment.setEquipmentCategory(equipmentCategoryMapper.selectById(equipment.getCategoryId()));
        }
        car.setEquipment(equipment);
        return car;
    }

    public List<CarIndexVo> getCarsInfoByOrgCode(String orgCode) {
        return carMapper.getCarsInfoByOrgCode(orgCode);
    }

    private List<UploadFile> getCarFileList(Long id, String type) {
        List<UploadFile> list = iUploadFileService.list(new QueryWrapper<UploadFile>().eq("object_id", id)
                .eq("object_type", BillContentEnum.CL.getKey()).eq("file_type", type));
        list.forEach(item -> {
            item.setUrl(fileServer + item.getUrl());
        });
        return list;
    }

    @Override
    public boolean removeOneByIds(List<Long> idList) {
        iCarPropertyService.remove(new QueryWrapper<CarProperty>().in("car_id", idList));
        boolean b = this.removeByIds(idList);
        if (b && syncSwitch) {
            syncDataService.syncDeletedFireVehicle(idList);
        }
        return b;
    }

    @Override
    public Page<Car> page(Page<Car> pageBean, Car car) {
        List<Car> list = carMapper.page(pageBean.offset(), pageBean.getSize(), car);
        int count = carMapper.count(car);
        pageBean.setRecords(list);
        pageBean.setTotal(count);
        return pageBean;
    }

    @Override
    public List<CarIndexVo> getCarsIotInfo(String orgCode) {
        return carMapper.getCarsIotInfo(orgCode);
    }

    @Override
    public List<EquipStateOnCarVo> getCarEquipmentsById(Long id) {
        List<EquipStateOnCarVo> list = carMapper.getCarEquipmentStateByCarId(id);
        List<EquipStateOnCarVo> result = new ArrayList<>();
        StringBuilder sb = new StringBuilder("equipmentOnCar_");
        if (list.size() > 0) {
            for (EquipStateOnCarVo carVo : list) {
                String key = sb.append(carVo.getIotCode()).toString();
                if (!ObjectUtils.isEmpty(redisUtils.get(key))) {
                    carVo.setState(TrueOrFalseEnum.real.value);
                } else {
                    carVo.setState(TrueOrFalseEnum.fake.value);
                }
                result.add(carVo);
            }
        }
        return result;
    }

    @Override
    @Transactional
    public Boolean updateCarStatus(List<CarStatusInfoDto> cars) {
        try {
            if (!ValidationUtil.isEmpty(cars)) {
                List<String> carIdList = Lists.transform(cars, CarStatusInfoDto::getSequenceNbr);
                List<Car> carList = carMapper.selectBatchIds(carIdList);
                Map<String, String> carStatusMap =
                        cars.stream().collect(Collectors.toMap(CarStatusInfoDto::getSequenceNbr, CarStatusInfoDto::getStatus));
                carList.forEach(car -> {
                    String carStatusCode = carStatusMap.get(car.getId().toString());
                    // 可进行更新操作
                    if (CarStatusEnum.getEnum(car.getCarState()).getAllowedOp().contains(carStatusCode)) {
                        // 更新车辆状态
                        car.setCarState(carStatusCode);
                    }
                });
                this.updateBatchById(carList);
            }
        } catch (Exception e) {
            throw new RuntimeException("操作失败！");
        }

        return true;
    }

    @Override
    public List<CarDto> getTeamCarList(Long id, Double longitude, Double latitude) {
        List<CarDto> list = carMapper.getTeamCarList(id, carState);
        if (!CollectionUtils.isEmpty(list)) {
            if (longitude != null && latitude != null) {
                List<Long> idList = list.stream().map(CarDto::getSequenceNbr).collect(Collectors.toList());
                List<CarPropertyVo> propertyList = getCarPropertyList(idList, null, nameKeys, 1);
                if (!CollectionUtils.isEmpty(propertyList)) {
                    list.stream().forEach(x -> {
                        List<CarPropertyVo> collect = propertyList.stream().filter(y -> y.getCarId().equals(x.getSequenceNbr())).collect(Collectors.toList());
                        final Double[] longitudeVal = {null};
                        final Double[] latitudeVal = {null};
                        collect.stream().forEach(z -> {
                            String nameKey = z.getNameKey();
                            String value = z.getValue();
                            switch (nameKey) {
                                case "FireCar_GDLongitude":
                                    if (StringUtils.isNotBlank(value)) {
                                        longitudeVal[0] = Double.parseDouble(value);
                                        x.setLongitude(String.valueOf(longitudeVal[0]));
                                    }
                                    break;
                                case "FireCar_GDLatitude":
                                    if (StringUtils.isNotBlank(value)) {
                                        latitudeVal[0] = Double.parseDouble(value);
                                        x.setLatitude(String.valueOf(latitudeVal[0]));
                                    }
                                    break;
                            }
                        });
                        if (longitudeVal[0] != null && latitudeVal[0] != null) {
                            GlobalCoordinates source = new GlobalCoordinates(longitudeVal[0], latitudeVal[0]);
                            GlobalCoordinates target = new GlobalCoordinates(longitude, latitude);
                            double distance = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.Sphere, source, target).getEllipsoidalDistance();
                            BigDecimal decimal = new BigDecimal(distance / 1000);
                            x.setDistance(decimal.setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue());
                        }
                    });
                }
            }
            return list;
        }
        return Lists.newArrayList();
    }

    @Override
    public List<CarPropertyVo> getCarPropertyList(List<Long> idList, Long teamId, String nameKeys, Integer isIot) {
        List<CarPropertyVo> list = carMapper.getCarPropertyList(idList, teamId, nameKeys, isIot);
        if (!CollectionUtils.isEmpty(list)) {
            return list;
        }
        return Lists.newArrayList();
    }

    @Override
    public Car querySimpleInfoById(Long carId) {
        return this.getById(carId);
    }

	@Override
	public Object getCarStateInfoByCarNum(String carNum) {
		// TODO Auto-generated method stub
		return carMapper.getCarStateInfoByCarNum(carNum);
	}



    @Override
    public CarForUE4VO getCarDetailByCarNumToThreeDimensional(Long carId, String orgCode) {
        CarForUE4VO carForUE4VO = new CarForUE4VO();
        QueryWrapper<Car> carQueryWrapper = new QueryWrapper<>();
        carQueryWrapper.eq("id", carId);
        Car car = carMapper.selectOne(carQueryWrapper);
        carForUE4VO.setId(carId);
        carForUE4VO.setCarNum(car.getCarNum());
        Equipment equipment = iEquipmentService.getById(car.getEquipmentId());
        if (!ObjectUtils.isEmpty(equipment.getCategoryId())) {
            equipment.setEquipmentCategory(equipmentCategoryMapper.selectById(equipment.getCategoryId()));
        }
        carForUE4VO.setCarType(equipment.getEquipmentCategory().getName());

        // 数据库字段（is_import 0->国产， 1->进口）
        carForUE4VO.setIsImport(Boolean.TRUE == car.getIsImport() ? TrueOrFalseEnum.real.desc : TrueOrFalseEnum.fake.desc);
        carForUE4VO.setBrand(car.getBrand());
        QueryWrapper<SystemDic> countryQueryWrapper = new QueryWrapper<>();
        countryQueryWrapper.eq("id", car.getCountry());
        SystemDic systemDic = iSystemDicService.getBaseMapper().selectOne(countryQueryWrapper);
        carForUE4VO.setCountry(systemDic.getName());
        carForUE4VO.setStandard(car.getStandard());
        ManufacturerInfo manufacturerInfo = iManufacturerInfoService.getById(car.getManufacturerId());
        carForUE4VO.setManufacturerName(manufacturerInfo.getName());
        carForUE4VO.setCccAuth(Boolean.TRUE == car.getCccAuth() ? TrueOrFalseEnum.real.flag : TrueOrFalseEnum.fake.flag);
        QueryWrapper<SystemDic> chassisCountryQueryWrapper = new QueryWrapper<>();
        chassisCountryQueryWrapper.eq("id", car.getChassisCountry());
        SystemDic dic = iSystemDicService.getBaseMapper().selectOne(chassisCountryQueryWrapper);
        carForUE4VO.setChassisCountry(dic.getName());
        carForUE4VO.setChassisBrand(car.getChassisBrand());
        return carForUE4VO;
    }



    @Override
    public Page<CarInfoDto> equipmentCarList(Page<CarInfoDto> pag, Long teamId, String name, String code, Long id,Boolean isNo) {


        List<Car> carList =carMapper.equipmentCarList(pag.offset(), pag.getSize(), teamId,  name, code,id,isNo);
       int num =carMapper.equipmentCarListcount( teamId,  name, code,id,isNo);

        List<Equipment> equipmentList = iEquipmentService.list();
        Map<Long, Equipment> keyMap = equipmentList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        List<EquipmentCategory> categoryList = iEquipmentCategoryService.list();
        Map<Long, String> categoryMap = categoryList.stream().collect(Collectors.toMap(BaseEntity::getId, EquipmentCategory::getName));
        List<UploadFile> fileList = iUploadFileService.list(new LambdaQueryWrapper<UploadFile>()
                .eq(UploadFile::getObjectType, "car")
                .eq(UploadFile::getFileType, "image"));

        // 车载装备
        List<Map<String, Object>> carResourceMapList = this.baseMapper.getCarResourceMapList(null);
        Map<String, List<Map<String, Object>>> carResourceMap =
                carResourceMapList.stream().collect(Collectors.groupingBy(car -> car.get("carId").toString()));
        List<CarInfoDto> CarInfoDtoList= carList.stream().map(car -> {
            CarInfoDto carInfoVo = new CarInfoDto();
            Bean.copyExistPropertis(car, carInfoVo);
            Equipment equipment = keyMap.get(carInfoVo.getEquipmentId());
            carInfoVo.setCarStateDesc(this.getCarStateDesc(car));
            carInfoVo.setEquipmentName(equipment != null ? equipment.getName() : "");
            carInfoVo.setCategoryId(equipment != null ? equipment.getCategoryId() : null);
            carInfoVo.setCategoryName(categoryMap.get(carInfoVo.getCategoryId()));


            carInfoVo.setImage(fileList.stream().filter(f -> f.getObjectId().equals(car.getId())).map(UploadFile::getUrl).collect(Collectors.toList()));

            if (equipment.getImg() != null){
                List<String> img = new ArrayList<>();
                img.add(equipment.getImg());
                carInfoVo.setImage(img);
            }


            carInfoVo.setResourceList(carResourceMap.get(car.getId().toString()));
            return carInfoVo;
        }).collect(Collectors.toList());

        pag.setTotal(num);
        pag.setRecords(CarInfoDtoList);
        return pag;
    }

    @Override
    public List<CarFusionDto> getCarFusionList() {
        List<CarFusionDto> carFusionDtos = this.baseMapper.selectCarAndCarProperty();
        return carFusionDtos;
    }
}
