package com.sckw.fleet.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.common.enums.enums.FileEnum;
import com.sckw.core.exception.SystemException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.EntTypeEnum;
import com.sckw.core.model.enums.SystemTypeEnum;
import com.sckw.core.model.file.FileInfo;
import com.sckw.core.utils.*;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginEntHolder;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.request.HttpClientUtil;
import com.sckw.core.web.response.HttpResult;
import com.sckw.excel.easyexcel.ExcelImportListener;
import com.sckw.excel.utils.ExcelUtil;
import com.sckw.fleet.dao.*;
import com.sckw.fleet.model.*;
import com.sckw.fleet.model.dto.*;
import com.sckw.fleet.model.vo.*;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.RemoteUserService;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.SysDictResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.api.dubbo.TransportService;
import com.sckw.transport.api.model.dto.RWaybillOrderDto;
import com.sckw.transport.api.model.vo.RTruckMonitorVo;
import com.sckw.transport.api.model.vo.RWaybillOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zk
 * @desc 车辆
 * @date 2023/7/6 0006
 */
@Slf4j
@Service
@SuppressWarnings("all")
@Transactional(rollbackFor = Exception.class)
public class KwfTruckService {

    @Autowired
    KwfTruckMapper truckDao;
    @Autowired
    KwfTruckEntMapper truckEntDao;
    @Autowired
    KwfTruckLicenseMapper truckLicenseDao;
    @Autowired
    KwfTransportLicenseMapper transportLicenseDao;
    @Autowired
    KwfTruckImportMapper kwfTruckImportDao;
    @Autowired
    KwfFleetTruckMapper fleetTruckDao;
    @DubboReference(version = "1.0.0", group = "design", check = false,timeout = 8000)
    private RemoteSystemService remoteSystemService;
    @DubboReference(version = "1.0.0", group = "design", check = false,timeout = 8000)
    private RemoteUserService remoteUserService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TransportService transportDubboService;

    /**
     * @param key 主键id
     * @desc 根据主键查询
     * @author zk
     * @date 2023/7/6
     **/
    public KwfTruck selectByKey(Long key) {
        return truckDao.selectById(key);
    }

    /**
     * @param truckId 车辆档案ID
     * @desc 车辆详情
     * @author zk
     * @date 2023/7/11
     **/
    public KwfTruckDetailVo detail(Long truckId){
        //车辆信息
        KwfTruck truck = this.selectByKey(truckId);
        KwfTruckDetailVo truckDetailVo = new KwfTruckDetailVo();
        BeanUtils.copyPropertiesValue(truck, truckDetailVo);

        //数据组装
        if (truck != null) {
            //车辆行驶证信息
            KwfTruckLicense truckLicense = this.findTruckLicenseByKey(truckId);
            KwfTruckLicenseVo truckLicenseVo = new KwfTruckLicenseVo();
            BeanUtils.copyPropertiesValue(truckLicense, truckLicenseVo);
            truckDetailVo.setTruckLicense(truckLicenseVo);

            //车辆道路运输许可证
            KwfTransportLicense transportLicense = this.findTransportLicenseByKey(truckId);
            KwfTransportLicenseVo transportLicenseVo = new KwfTransportLicenseVo();
            BeanUtils.copyPropertiesValue(transportLicense, transportLicenseVo);
            truckDetailVo.setTransportLicense(transportLicenseVo);

            //字典
            String value = getDictValue(DictTypeEnum.COLOR_TYPE.getType(), StringUtils.objectStr(truck.getColor()));
            truckDetailVo.setColorName(value);

            //车队班组
            KwfFleet fleet = this.findByFleetTruck(truckId, LoginUserHolder.getEntId());
            truckDetailVo.setFleetId(fleet != null ? fleet.getId() : null);
            truckDetailVo.setFleetName(fleet != null ? fleet.getName() : null);
            return truckDetailVo;
        }
        return null;
    }

    /**
     * @param params 参数
     * @desc 统计
     * @author zk
     * @date 2023/7/11
     **/
    public Map statistics(Map<String, Object> params) {
        /**统计数据**/
        List<KwfTableTopCount> counts = statisticsHandle(params);
        long tatol = 0;
        for (KwfTableTopCount topCount:counts) {
            tatol += topCount.getTotal();
        }

        /**全部数据-处理**/
        List<KwfTableTopCount> countList = new ArrayList();
        KwfTableTopCount allCount = new KwfTableTopCount();
        allCount.setValue(String.valueOf(Global.NUMERICAL_ZERO));
        allCount.setTotal(tatol);
        allCount.setName("全部");
        countList.add(allCount);

        /**数据处理**/
        Map<String, Integer> authStatusMap = new HashMap(){{put("正常", 1); put("临时", 2); put("异常", 3);}};
        for(Map.Entry<String, Integer> entry:authStatusMap.entrySet()){
            KwfTableTopCount count = new KwfTableTopCount();
            for (KwfTableTopCount topCount:counts) {
                if (Integer.parseInt(topCount.getValue()) == entry.getValue()) {
                    BeanUtils.copyProperties(topCount, count);
                }
            }
            count.setName(entry.getKey());
            count.setValue(String.valueOf(entry.getValue()));
            countList.add(count);
        }

        /**数据组装**/
        Map tableCount = new HashMap();
        tableCount.put("tableTop", countList);
        tableCount.put("tableBottom", tatol);
        return tableCount;
    }

    /**
     * @param params 参数
     * @desc 统计
     * @author zk
     * @date 2023/9/11
     **/
    public List<KwfTableTopCount> statisticsHandle(Map<String, Object> params) {
        int systemType = LoginUserHolder.getSystemType();
        /**统计数据**/
        if (systemType == SystemTypeEnum.MANAGE.getCode()) {
            List<KwfTableTopCount> counts = truckDao.statisticsAll(params);
            return counts;
        } else {
            Object keywords = params.get("keywords");
            if (StringUtils.isNotBlank(keywords)) {
                //查询企业
                List<Integer> entTypes = new ArrayList<>(){{add(EntTypeEnum.LOGISTICS3.getCode()); add(EntTypeEnum.LOGISTICS4.getCode());}};
                List<Long> entIds = remoteUserService.findEntIds(entTypes, StringUtils.objectStr(keywords));
                params.put("entIds", entIds);
                //查询用户
                List<Long> userIds = remoteUserService.findUserIds(new ArrayList<>(){{add(LoginUserHolder.getEntId());}}, StringUtils.objectStr(keywords));
                params.put("createBys", userIds);
            }
            params.put("entId", LoginUserHolder.getEntId());
            List<KwfTableTopCount> counts = truckDao.statistics(params);
            return counts;
        }
    }

    /**
     * @param params 分页参数
     * @desc 分页查询
     * @author zk
     * @date 2023/7/6
     **/
    public List<KwfTruckVo> findPage(Map<String, Object> params) {
        /**查询分页数据**/
        List<KwfTruckVo> trucks = findPageHandle(params);
        if (CollectionUtils.isEmpty(trucks)) {
            return trucks;
        }

        /**获取查询数据**/
        String pound = Global.POUND;
        List<Long> createBys = new ArrayList<>();
        List<Long> entIds = new ArrayList<>();
        List<String> dictKey = new ArrayList<>();

        for (KwfTruckVo truck:trucks) {
            createBys.add(Long.parseLong(truck.getCreateBy()));
            entIds.add(Long.parseLong(truck.getEntId()));
            dictKey.add(truck.getColor() != null ? DictTypeEnum.COLOR_TYPE.getType() + pound + truck.getColor() : null);
            dictKey.add(truck.getColor() != null ? DictTypeEnum.TRUCK_TYPE.getType() + pound + truck.getType() : null);
            dictKey.add(truck.getColor() != null ? DictTypeEnum.USE_TYPE.getType() + pound + truck.getUseType() : null);
            dictKey.add(truck.getColor() != null ? DictTypeEnum.ENERGY_TYPE.getType() + pound + truck.getEnergyType() : null);
        }
        //用户数据集
        createBys = createBys.stream().distinct().collect(Collectors.toList());
        Map<Long, UserCacheResDto> users = remoteSystemService.queryUserCacheMapByIds(createBys);
        //企业数据集
        entIds = entIds.stream().distinct().collect(Collectors.toList());
        Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);
        //数据字典
        Map<String, SysDictResDto> dicts = this.dict(dictKey);

        /**数据组装**/
        for (KwfTruckVo truck:trucks) {
            UserCacheResDto user = users == null ? null : users.get(Long.parseLong(truck.getCreateBy()));
            EntCacheResDto ent = ents == null ? null : ents.get(Long.parseLong(truck.getEntId()));
            SysDictResDto color = dicts.get(DictTypeEnum.COLOR_TYPE.getType() + pound + truck.getColor());
            SysDictResDto type = dicts.get(DictTypeEnum.TRUCK_TYPE.getType() + pound + truck.getType());
            SysDictResDto useType = dicts.get(DictTypeEnum.USE_TYPE.getType() + pound + truck.getUseType());
            SysDictResDto energyType = dicts.get(DictTypeEnum.ENERGY_TYPE.getType() + pound + truck.getEnergyType());
            truck.setCreateByName(user != null ? user.getName() : null);
            truck.setFirmName(ent != null ? ent.getFirmName() : null);
            truck.setColorName(color != null ? color.getLabel() : null);
            truck.setTruckTypeName(type != null ? type.getLabel() : null);
            truck.setUseTypeName(useType != null ? useType.getLabel() : null);
            truck.setEnergyTypeName(energyType != null ? energyType.getLabel() : null);
        }
        return trucks;
    }

    /**
     * @param params 分页参数
     * @desc 分页查询
     * @author zk
     * @date 2023/7/6
     **/
    public List<KwfTruckVo> findPageHandle(Map<String, Object> params) {
        int systemType = LoginUserHolder.getSystemType();
        /**统计数据**/
        if (systemType == SystemTypeEnum.MANAGE.getCode()) {
            List<KwfTruckVo> counts = truckDao.findPageAll(params);
            return counts;
        } else {
            Object keywords = params.get("keywords");
            if (StringUtils.isNotBlank(keywords)) {
                //查询企业
                List<Integer> entTypes = new ArrayList<>(){{add(EntTypeEnum.LOGISTICS3.getCode()); add(EntTypeEnum.LOGISTICS4.getCode());}};
                List<Long> entIds = remoteUserService.findEntIds(entTypes, StringUtils.objectStr(keywords));
                params.put("entIds", entIds);
                //查询用户
                List<Long> userIds = remoteUserService.findUserIds(new ArrayList<>(){{add(LoginUserHolder.getEntId());}}, StringUtils.objectStr(keywords));
                params.put("createBys", userIds);
            }
            params.put("entId", LoginUserHolder.getEntId());
            List<KwfTruckVo> counts = truckDao.findPage(params);
            return counts;
        }
    }

    /**
     * @param params 查询参数
     * @desc 查询
     * @author zk
     * @date 2023/7/6
     **/
    public List<Map<String, Object>> findList(Map<String, Object> params) {
        return truckDao.findList(params);
    }

    /**
     * @param {}
     * @desc 导出
     * @author zk
     * @date 2023/07/11
     **/
    public HttpResult importExcel(MultipartFile file) {/**文件存储**/
        importFileSave(file);

        /**参数校验**/
        HttpResult result = this.checkParams(file);
        if (result.getCode() != HttpStatus.SUCCESS_CODE) {
            return result;
        }

        /**数据处理**/
        int count = 0;
        List<KwfTruckExcelImportDto> truckExcels = (List)result.getData();
        for (KwfTruckExcelImportDto kwfTruckExcel:truckExcels) {
            //车辆信息
            KwfTruck truck = new KwfTruck();
            truck.setTruckNo(kwfTruckExcel.getTruckNo());
            truck.setActualWeight(new BigDecimal(kwfTruckExcel.getActualWeight()));
            truck.setAuthStatus(Global.NUMERICAL_TWO);
            result = truckEdit(truck);
            if (result.getCode() == HttpStatus.SUCCESS_CODE) {
                count ++;
            }
        }

        return HttpResult.ok("成功导入"+count+"行数据！");
    }

    /**
     * @param params 参数
     * @desc 新增车辆
     * @author zk
     * @date 2023/7/6
     **/
    public HttpResult add(KwfTruckDto params) {
        /**车辆信息**/
        KwfTruck truck = new KwfTruck();
        BeanUtils.copyProperties(params, truck);
        //证件都有数据则为已认证(前端校验认证数据必填)
        boolean bool = checkLicense(params);
        if (bool) {
            truck.setAuthStatus(Global.NUMERICAL_ONE);
        } else {
            truck.setAuthStatus(Global.NUMERICAL_TWO);
        }
        HttpResult result = truckEdit(truck);
        if (result.getCode() != HttpStatus.SUCCESS_CODE) {
            return result;
        }
        truck = (KwfTruck)result.getData();

        /**车辆行驶证信息**/
        KwfTruckLicenseDto truckLicenseDto = params.getTruckLicense();
        if (truckLicenseDto != null) {
            truckLicenseDto.setTruckId(truck.getId());
            truckLicenseEdit(truckLicenseDto);
        }

        /**车辆行驶证信息**/
        KwfTransportLicenseDto transportLicenseDto = params.getTransportLicense();
        if (transportLicenseDto != null) {
            transportLicenseDto.setTruckId(truck.getId());
            transportLicenseEdit(transportLicenseDto);
        }

        /**车队班组绑定**/
        truckFleetEdit(truck.getId(), params.getFleetId());

        return HttpResult.ok(result.getMsg(), truck);
    }

    /**
     * @param params 参数
     * @desc 修改车辆
     * @author zk
     * @date 2023/7/6
     **/
    public HttpResult update(KwfTruckDto params) {
        /**数据校验**/
        if (StringUtils.isBlank(params.getId())) {
            return HttpResult.error(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE,"车辆信息ID不能为空！");
        }
        KwfTruck truck = truckDao.selectById(params.getId());
        if (truck == null) {
            return HttpResult.error("车辆信息不存在！");
        }

        /**车辆信息**/
        BeanUtils.copyProperties(params, truck);
        //证件都有数据则为已认证(前端校验认证数据必填)
        boolean bool = checkLicense(params);
        if (bool) {
            truck.setAuthStatus(Global.NUMERICAL_ONE);
        }
        HttpResult result = truckEdit(truck);
        if (result.getCode() != HttpStatus.SUCCESS_CODE) {
            return result;
        }

        /**车辆行驶证信息**/
        KwfTruckLicenseDto truckLicenseDto = params.getTruckLicense();
        if (truckLicenseDto != null) {
            truckLicenseDto.setTruckId(truck.getId());
            truckLicenseEdit(truckLicenseDto);
        }

        /**车辆行驶证信息**/
        KwfTransportLicenseDto transportLicenseDto = params.getTransportLicense();
        if (transportLicenseDto != null) {
            transportLicenseDto.setTruckId(truck.getId());
            transportLicenseEdit(transportLicenseDto);
        }

        /**车队班组绑定**/
        truckFleetEdit(truck.getId(), params.getFleetId());
        return HttpResult.ok("车辆信息修改成功！");
    }

    /**
     * @param {ids：主键ID（多个以逗号隔开）}
     * @description 删除
     * @author zk
     * @date 2023/7/6
     **/
    public HttpResult del(String ids) {
        /**数据校验**/
        if (StringUtils.isBlank(ids)) {
            return HttpResult.error("请选择要删除的数据！");
        }

        /**数据组装**/
        String[] idArray = ids.split(",");
        KwfTruckEnt truckEntQuery = new KwfTruckEnt();
        truckEntQuery.setEntId(LoginUserHolder.getEntId());
        for (String id : idArray) {
            truckEntQuery.setTruckId(Long.parseLong(id));
            KwfTruckEnt truckEnt = truckEntDao.findByTruckEnt(truckEntQuery);
            if (truckEnt != null) {
                truckEnt.setDelFlag(Global.YES);
                if (truckEntDao.updateById(truckEnt) <= 0) {
                    throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.DELETE_FAIL);
                }
            } else {
                return HttpResult.error("选择删除的数据已不存在！");
            }
        }
        return HttpResult.ok("删除成功！");
    }

    /**
     * @param params 参数
     * @desc 更新车辆信息
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult truckEdit(KwfTruck params) {
        if (StringUtils.isBlank(params.getId())) {
            /**唯一性交易**/
            List<KwfTruck> trucks = truckDao.findTruck(new HashMap(){{ put("truckNo", params.getTruckNo()); }});
            if (CollectionUtils.isEmpty(trucks)) {
                /**新增**/
                params.setEntId(LoginUserHolder.getEntId());
                params.setEntId(params.getEntId() == null ? 1 : params.getEntId());// 暂时处理---------------zk
                params.setBusinessStatus(Global.NO);
                params.setStatus(Global.NO);
                int count = truckDao.insert(params);

                /**车辆信息与企业关联信息**/
                truckEntEdit(params);
                return count > 0 ? HttpResult.ok(params) : HttpResult.error("车辆信息新增失败！");
            } else {
                KwfTruck truck = trucks.get(Global.NUMERICAL_ZERO);
                BeanUtils.copyPropertiesValue(params, truck);
                int count = truckDao.updateById(truck);

                /**车辆信息与企业关联信息**/
                KwfTruck truckEnt = new KwfTruck();
                truckEnt.setEntId(LoginUserHolder.getEntId());
                truckEnt.setId(truck.getId());
                truckEntEdit(truckEnt);
                return count > 0 ? HttpResult.ok("车辆信息修改成功！", truck) : HttpResult.error("车辆信息修改失败！");
            }
        } else {
            /**唯一性交易**/
            List<KwfTruck> trucks = truckDao.findTruck(new HashMap(){{ put("truckNo", params.getTruckNo()); }});
            //校验list中对象key值是否存在与value不一致的情况
            boolean bool = listByKeyValue(trucks, params.getId());
            if (bool) {
                return HttpResult.error("车牌号已存在！");
            }

            /**更新**/
            int count = truckDao.updateById(params);
            return count > 0 ? HttpResult.ok("车辆信息修改成功！", params) : HttpResult.error("车辆信息修改失败！");
        }
    }

    /**
     * @param params 参数
     * @desc 更新车辆行驶证信息
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult truckLicenseEdit(KwfTruckLicenseDto params) {
        /**数据copy**/
        KwfTruckLicense truckLicense = new KwfTruckLicense();
        BeanUtils.copyProperties(params, truckLicense);
        truckLicense.setStatus(Global.YES);
        String certificateMain = truckLicense.getCertificateMain();
        String certificateRevolt = truckLicense.getCertificateRevolt();
        if (StringUtils.isBlank(certificateMain) && StringUtils.isBlank(certificateRevolt)) {
            truckLicense.setStatus(Global.NO);
            truckLicense.setCertificateMain(Global.EMPTY_STRING);
            truckLicense.setCertificateRevolt(Global.EMPTY_STRING);
        }
        truckLicense.setCertificateMain(StringUtils.isBlank(certificateMain)
                ? Global.EMPTY_STRING : truckLicense.getCertificateMain());
        truckLicense.setCertificateRevolt(StringUtils.isBlank(certificateRevolt)
                ? Global.EMPTY_STRING : truckLicense.getCertificateRevolt());

        /**数据更新**/
        int count = 0;
        KwfTruckLicense license = truckLicenseDao.findByTruckId(params.getTruckId());
        if (license == null) {
            count = truckLicenseDao.insert(truckLicense);
        } else {
            truckLicense.setId(license.getId());
            count = truckLicenseDao.updateById(truckLicense);
        }

        /**校验车辆是否有证书并更新状态**/
        checkLicense(truckLicense.getId());
        return count > 0 ? HttpResult.ok("车辆行驶证信息修改成功！") : HttpResult.error("车辆行驶证信息修改失败！");
    }

    /**
     * @param key 参数
     * @desc 查询车辆行驶证信息
     * @author zk
     * @date 2023/7/7
     **/
    public KwfTruckLicense findTruckLicenseByKey(Long key) {
        return truckLicenseDao.findByTruckId(key);
    }

    /**
     * @param params 参数
     * @desc 更新车辆道路运输许可证
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult transportLicenseEdit(KwfTransportLicenseDto params) {
        /**数据copy**/
        KwfTransportLicense transportLicense = new KwfTransportLicense();
        BeanUtils.copyProperties(params, transportLicense);
        transportLicense.setStatus(Global.YES);
        String certificateMain = transportLicense.getCertificateMain();
        String certificateRevolt = transportLicense.getCertificateRevolt();
        if (StringUtils.isBlank(certificateMain) && StringUtils.isBlank(certificateRevolt)) {
            transportLicense.setStatus(Global.NO);
            transportLicense.setCertificateMain(Global.EMPTY_STRING);
            transportLicense.setCertificateRevolt(Global.EMPTY_STRING);
        }
        transportLicense.setCertificateMain(StringUtils.isBlank(certificateMain)
                ? Global.EMPTY_STRING : transportLicense.getCertificateMain());
        transportLicense.setCertificateRevolt(StringUtils.isBlank(certificateRevolt)
                ? Global.EMPTY_STRING : transportLicense.getCertificateRevolt());

        /**数据更新**/
        int count = 0;
        KwfTransportLicense license = transportLicenseDao.findByTruckId(params.getTruckId());
        if (license == null) {
            count = transportLicenseDao.insert(transportLicense);
            return count > 0 ? HttpResult.ok("车辆驾驶证信息更新成功！") : HttpResult.error("车辆驾驶证信息更新失败！");
        } else {
            transportLicense.setId(license.getId());
            count = transportLicenseDao.updateById(transportLicense);
        }

        /**校验车辆是否有证书并更新状态**/
        checkLicense(transportLicense.getTruckId());
        return count > 0 ? HttpResult.ok("车辆驾驶证信息修改成功！") : HttpResult.error("车辆驾驶证信息修改失败！");
    }

    /**
     * @param key 参数
     * @desc 查询车辆道路运输许可证
     * @author zk
     * @date 2023/7/7
     **/
    public KwfTransportLicense findTransportLicenseByKey(Long key) {
        return transportLicenseDao.findByTruckId(key);
    }

    /**
     * @param params 参数
     * @desc 新增车辆信息与企业关联信息
     * @author zk
     * @date 2023/7/7
     **/
    public int truckEntEdit(KwfTruck params) {
        KwfTruckEnt truckEnt = new KwfTruckEnt();
        truckEnt.setTruckId(params.getId());
        truckEnt.setEntId(params.getEntId() == null ? LoginUserHolder.getEntId() : params.getEntId());
        KwfTruckEnt ent = truckEntDao.findByTruckEnt(truckEnt);
        if (ent == null) {
            int count = truckEntDao.insert(truckEnt);
            return count;
        }
        return Global.MINUS_ONE;
    }

    /**
     * @param truckId 车辆档案主键id fleetId 车队班组主键id
     * @desc 车队班组绑定
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult truckFleetEdit(Long truckId, Long fleetId) {
        /**数据校验**/
        if (fleetId == null) {
            return HttpResult.ok("未选择车队班组！");
        }
        KwfFleetTruck queryFleetTruck = new KwfFleetTruck();
        queryFleetTruck.setEntId(LoginUserHolder.getEntId());
        queryFleetTruck.setTruckId(truckId);
        KwfFleetTruck fleetTruck = fleetTruckDao.findByTruckFleet(queryFleetTruck);

        /**数据更新**/
        queryFleetTruck.setFleetId(fleetId);
        if (fleetTruck == null) {
            int count = fleetTruckDao.insert(queryFleetTruck);
            return count > 0 ? HttpResult.ok("车队班组绑定成功！") : HttpResult.error("车队班组绑定失败！");
        } else {
            queryFleetTruck.setId(fleetTruck.getId());
            int count = fleetTruckDao.updateById(queryFleetTruck);
            return count > 0 ? HttpResult.ok("车队班组绑定成功！") : HttpResult.error("车队班组绑定失败！");
        }
    }

    /**
     * @param truckId 车辆id
     * @param entId 企业id
     * @desc 查询车队班组
     * @author zk
     * @date 2023/7/20
     **/
    public KwfFleet findByFleetTruck(Long truckId, Long entId){
        return fleetTruckDao.findByFleetTruck(truckId, entId);
    }

    /**
     * @param file 上传文件
     * @desc 上传文件持久化
     * @author zk
     * @date 2023/7/6
     **/
    public void importFileSave(MultipartFile file) {
        FileInfo fileInfo = FileUtils.getFileDataList(file);
        fileInfo.setType(FileEnum.FILE_STORE_TYPE_OSS.getFileType());
        FileInfo returnFileInfo = FileUtils.uploadFileInfo(file, fileInfo, FileEnum.FILE_STORE_TYPE_OSS);

        KwfTruckImport truckImport = new KwfTruckImport();
        truckImport.setEntId(LoginUserHolder.getEntId());
        truckImport.setUrl(returnFileInfo.getFilePath());
        truckImport.setRemark(JSON.toJSONString(returnFileInfo));
        kwfTruckImportDao.insert(truckImport);

        try {
            //remoteFileService.fileInfoInsert(fileInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @desc 企业车辆统计
     * @author zk
     * @date 2023/9/18
     **/
    public Map<String, Object> truckStatistics() {
        return truckDao.truckStatistics(LoginUserHolder.getEntId());
    }

    /**
     * @param params {truckNo 車牌號}
     * @desc 车辆查询(业务关联+归属车辆)
     * @author zk
     * @date 2023/9/5
     **/
    public List<KwfTruckMonitorVo> findTruck(Map params){
        long begTime = System.currentTimeMillis();
        /**车辆查询**/
        Map queryParams = new HashMap<>(Global.NUMERICAL_SIXTEEN){{ put("truckNo", params.get("truckNo"));}};
        List<KwfTruckMonitorVo> truckList = findTruckMonitor(queryParams);
        if (truckList == null || truckList.size() == 0) {
            return truckList;
        }

        /**数据配置**/
        List<Long> entIds = new ArrayList<>();
        List<String> truckNos = new ArrayList<>();
        for (KwfTruckMonitorVo truck:truckList) {
            entIds.add(truck.getEntId());
            truckNos.add(truck.getTruckNo());
        }
        long begTime1 = System.currentTimeMillis();
        log.info("获取数据="+(begTime1 - begTime));
        //企业数据集
        entIds = entIds.stream().distinct().collect(Collectors.toList());
        Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);
        //车辆定位数据集
        Map<String, KwfTruckGpsVo> truckGpsMap = findTruckLocateHandle(truckNos);
        long begTime2 = System.currentTimeMillis();
        log.info("获取GPS="+(begTime2 - begTime1));

        /**数据组装**/
        for (KwfTruckMonitorVo truck:truckList) {
            EntCacheResDto ent = ents == null ? null : ents.get(truck.getEntId());
            KwfTruckGpsVo truckGps = truckGpsMap != null ? truckGpsMap.get(truck.getTruckNo()) : null;
            truck.setFirmName(ent != null ? ent.getFirmName() : null);
            truck.setRunStatus(truckGps != null ? truckGps.getRunStatus() : null);
        }
        long begTime3 = System.currentTimeMillis();
        log.info("数据组装="+(begTime3 - begTime2));
        return truckList;
    }

    /**
     * @param truckNos 車牌號集
     * @description 车辆查询GPS(业务关联 + 归属车辆)
     * @author zk
     * @date 2023/9/6
     **/
    public List<KwfTruckGpsVo> findTruckGps(List<String> truckNos) {
        /**车辆查询**/
        List<KwfTruckGpsVo> truckGpsList = new ArrayList<>();
        Map<String, Object> queryParams = new HashMap<>(Global.NUMERICAL_SIXTEEN){{ put("truckNos", truckNos);}};
        List<KwfTruckMonitorVo> truckList = findTruckMonitor(queryParams);
        if (truckList == null || truckList.size() == 0) {
            return truckGpsList;
        }

        //车辆定位数据集
        Map<String, KwfTruckGpsVo> truckGpsMap = findTruckLocateHandle(truckNos);

        /**数据组装**/
        for (KwfTruckMonitorVo truck:truckList) {
            KwfTruckGpsVo truckGps = truckGpsMap != null ? truckGpsMap.get(truck.getTruckNo()) : null;
            if (truckGps == null) {
                continue;
            }
            truckGps.setTruckNo(truck.getTruckNo());
            truckGps.setBusinessStatus(truck.getBusinessStatus());
            truckGpsList.add(truckGps);
        }

        return truckGpsList;
    }

    /**
     * @param params 参数
     * @desc 车辆查询(业务关联 + 归属车辆)
     * @author zk
     * @date 2023/9/6
     **/
    public List<KwfTruckMonitorVo> findTruckMonitor(Map params) {
        //企业PC/APP
        if (LoginUserHolder.getSystemType() == SystemTypeEnum.COMPANY.getCode()) {
            List<KwfTruckMonitorVo> trucks = new ArrayList<>();
            //企业属性
            String entTypes = LoginEntHolder.get().getEntTypes();
            //承运方
            Boolean bool = EntTypeEnum.carrier(entTypes);
            if (bool != null && bool) {
                params.put("entId", LoginUserHolder.getEntId());
                List<KwfTruckMonitorVo> carrierTrucks = truckDao.findTruckByEnt(params);
                trucks.addAll(carrierTrucks);
            }

            //托运方
            bool = EntTypeEnum.check(entTypes);
            if (bool != null && bool) {
                List<RTruckMonitorVo> checkTrucks = transportDubboService.truckInTask(LoginUserHolder.getEntId());
                checkTrucks.forEach(order -> trucks.add(new KwfTruckMonitorVo(order.getEntId(), order.getTruckNo(), Global.NUMERICAL_ONE)));
            }

            return trucks;
        }

        //运营端
        if (LoginUserHolder.getSystemType() == SystemTypeEnum.MANAGE.getCode()) {
            return truckDao.findTruckByAll(params);
        }
        return new ArrayList<>();
    }

    /**
     * @param truckNo 车牌号
     * @desc 车牌号查询车辆关联数据
     * @author zk
     * @date 2023/9/6
     **/
    public Map<String, Object> findDetailByTruckNo(String truckNo) {
        //定位信息
        KwfTruckGpsVo truckGps = findTruckLocate(truckNo);
        //运单信息
        RWaybillOrderVo waybillOrder = getWaybillOrder(truckNo, Global.NUMERICAL_THREE);
        String firmName = LoginEntHolder.getFirmName();
        if (LoginUserHolder.getSystemType() == SystemTypeEnum.MANAGE.getCode()) {
            List<KwfTruck> trucks = truckDao.findTruck(new HashMap<>(Global.NUMERICAL_SIXTEEN){{put("truckNo", truckNo);}});
            KwfTruck truck = CollectionUtils.isEmpty(trucks) ? null : trucks.get(Global.NUMERICAL_ZERO);
            if (truck != null) {
                //企业数据集
                List<Long> entIds = new ArrayList<>() {{
                    add(truck.getEntId());
                }};
                Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);
                EntCacheResDto ent = ents == null ? null : ents.get(truck.getEntId());
                firmName = ent != null ? ent.getFirmName() : null;
            }
        }
        //详细地址
        String detailAddress = truckGps != null
                ? StringUtils.isNotBlank(truckGps.getDetailAddress())
                ? truckGps.getDetailAddress() : LocUtils.regeo(truckGps.getLng(), truckGps.getLat())
                : null;

        Map<String, Object> detail = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        detail.put("truckNo", truckNo);
        detail.put("firmName", firmName);
        detail.put("detailAddress", detailAddress);
        detail.put("speed", truckGps != null ? truckGps.getSpeed() : null);
        detail.put("gpsTime", truckGps != null ? truckGps.getGpsTime() : null);
        detail.put("driverName", waybillOrder != null ? waybillOrder.getDriverName() : null);
        detail.put("driverPhone", waybillOrder != null ? waybillOrder.getDriverPhone() : null);
        detail.put("startTime", waybillOrder != null ? DateUtils.formatV1(waybillOrder.getDepartureTime()) : null);
        detail.put("endTime", waybillOrder != null && waybillOrder.getDepartureTime() != null ? DateUtils.getCurrentTime() : null);
        detail.put("orderNo", waybillOrder != null ? waybillOrder.getWOrderNo() : null);
        return detail;
    }

    /**
     * @param type 字典类型
     * @param value 字典值
     * @desc 获取数据字典值
     * @author zk
     * @date 2023/8/30
     **/
    public String getDictValue(String type, String value) {
        if (StringUtils.isBlank(type) || StringUtils.isBlank(value)) {
            return null;
        }
        List<String> dictKey = new ArrayList<>(){{
            add(type + Global.POUND + value);
        }};
        Map<String, SysDictResDto> dicts = remoteSystemService.queryDictMapByTypeValues(String.join(Global.COMMA, dictKey));
        SysDictResDto dict = dicts == null ? null : dicts.get(DictTypeEnum.APPROVED_DRIVING.getType() + Global.POUND + value);
        return dict != null ? dict.getLabel() : null;
    }

    /**
     * @param dictKey 字典值
     * @desc 获取数据字典
     * @author zk
     * @date 2023/9/11
     **/
    public Map<String, SysDictResDto> dict(List<String> dictKey) {
        if (CollectionUtils.isEmpty(dictKey)) {
            return Collections.emptyMap();
        }
        dictKey = dictKey.stream().distinct().collect(Collectors.toList());
        return remoteSystemService.queryDictMapByTypeValues(String.join(Global.COMMA, dictKey));
    }

    /**
     * @param params 参数
     * @desc 校验车辆是否有证书
     * @author zk
     * @date 2023/7/11
     **/
    public boolean checkLicense(KwfTruckDto params) {
        //车辆行驶证信息
        KwfTruckLicenseDto license = params.getTruckLicense();
        if (license == null || (StringUtils.isBlank(license.getCertificateMain())
                && StringUtils.isBlank(license.getCertificateRevolt()))) {
            return false;
        }
        //车辆道路运输许可证
        KwfTransportLicenseDto transportLicense = params.getTransportLicense();
        if (transportLicense == null || (StringUtils.isBlank(transportLicense.getCertificateMain())
                && StringUtils.isBlank(transportLicense.getCertificateRevolt()))) {
            return false;
        }
        return true;
    }

    /**
     * @param truckId 车辆主键id
     * @desc 校验车辆是否有证书并更新状态
     * @author zk
     * @date 2023/7/11
     **/
    public void checkLicense(Long truckId) {
        //车辆行驶证信息
        KwfTruckLicense license = this.findTruckLicenseByKey(truckId);
        if (license == null || (StringUtils.isBlank(license.getCertificateMain())
                && StringUtils.isBlank(license.getCertificateRevolt()))) {
            return;
        }
        //车辆道路运输许可证
        KwfTransportLicense transportLicense = this.findTransportLicenseByKey(truckId);
        if (transportLicense == null || (StringUtils.isBlank(transportLicense.getCertificateMain())
                && StringUtils.isBlank(transportLicense.getCertificateRevolt()))) {
            return;
        }
        //更新数据
        KwfTruck truck = new KwfTruck();
        truck.setId(truckId);
        truck.setAuthStatus(Global.NUMERICAL_ONE);
        truckDao.updateById(truck);
    }

    /**
     * @param file 上传文件
     * @desc 参数校验
     * @author zk
     * @date 2023/8/16
     **/
    public HttpResult checkParams(MultipartFile file) {
        ExcelReader excelReader = null;
        try {
            /**数据校验**/
            if (ExcelUtil.checkExcel(file)) {
                return HttpResult.error("请上传Excel格式的文件！");
            }

            ExcelImportListener importListener = new ExcelImportListener();
            InputStream inputStream = file.getInputStream();
            excelReader = EasyExcel.read(inputStream, importListener).build();

            ReadSheet readSheet = EasyExcel.readSheet( 0) .headRowNumber(2).head(KwfTruckExcelImportDto .class).build();
            excelReader.read(readSheet);
            if (importListener.getErrorList().size() > 0) {
                return HttpResult.error(HttpStatus.GLOBAL_EXCEPTION_CODE, "数据格式不正确，请确认！", importListener.getErrorList());
            }
            if (importListener.getDataList().size() == 0) {
                return HttpResult.error("导入数据不能空！");
            }

            return HttpResult.ok(importListener.getDataList());
        } catch (Exception e) {
            e.printStackTrace();
            return HttpResult.error("车辆导入异常！");
        } finally {
            if (excelReader != null) {
                excelReader.finish();
            }
        }
    }

    /**
     * 校验list中对象key值是否存在与value不一致的情况
     * @param list 数据集
     * @param value 匹配值
     * @return
     */
    public static boolean listByKeyValue(List<KwfTruck> list, Long value) {
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        for (KwfTruck truck:list) {
            if (value != null && !truck.getId().equals(value)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param truckNos 车牌号
     * @desc 查询车辆定位数据
     * @author zk
     * @date 2023/9/5
     **/
    public Map<String, KwfTruckGpsVo> findTruckLocateHandle(List<String> truckNos){
        /**车牌号超过100则分批次请求数据**/
        int maxLimit = 500;
        List<List<String>> truckNoList = new ArrayList<List<String>>();
        List<String> findTruckSon = null;
        for (int i = 0; i < truckNos.size(); i++) {
            if (i % maxLimit == 0) {
                findTruckSon = new ArrayList<String>();
                truckNoList.add(findTruckSon);
            }
            findTruckSon.add(truckNos.get(i));
        }

        /**获取数据**/
        Map<String, KwfTruckGpsVo> truckGpsMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        for (List<String> turckNo:truckNoList) {
            Map<String, KwfTruckGpsVo> truckGps = findTruckLocate(turckNo);
            truckGpsMap.putAll(truckGps);
        }

        return truckGpsMap;
    }

    /**
     * @param truckNos 车牌号
     * @desc 查询车辆定位数据
     * @author zk
     * @date 2023/9/5
     **/
    public RWaybillOrderVo getWaybillOrder(String truckNo, int busStatus) {
        try {
            List<RWaybillOrderVo> waybillOrders = transportDubboService.findWaybillOrder(new RWaybillOrderDto(truckNo, busStatus));
            if (CollectionUtils.isEmpty(waybillOrders)) {
                return null;
            }
            return waybillOrders.get(Global.NUMERICAL_ZERO);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Value("${external.openapi.queryLocate}")
    private String queryLocate;
    @Value("${external.openapi.queryLocateTrack}")
    private String queryLocateTrack;

    /**
     * @param truckNos 车牌号
     * @desc 查询车辆定位数据
     * @author zk
     * @date 2023/9/5
     **/
    public Map<String, KwfTruckGpsVo> findTruckLocate(List<String> truckNos){
        Map<String, KwfTruckGpsVo> truckGpsMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        if (truckNos == null || truckNos.size() == 0) {
            return truckGpsMap;
        }

        try {
            Map<String, Object> params = new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                put("vehicleNoList", truckNos);
            }};

            long begTime = System.currentTimeMillis();
            String httpResult = HttpClientUtil.post(queryLocate, JSON.toJSONString(params));
            long entTime = System.currentTimeMillis();
            if (StringUtils.isNotBlank(httpResult)) {
                JSONObject result = JSONObject.parseObject(httpResult);
                if (result.getInteger("code") != null && result.getInteger("code") != 200) {
                    return truckGpsMap;
                }
                JSONArray trucks = result.getJSONArray("data");
                //log.info("车牌号数量="+ truckNos.size() + " GPS数量=" + (trucks != null ? trucks.size() : 0) + " 响应时间="+(entTime - begTime));
                for (int i=0; trucks != null && i < trucks.size(); i++) {
                    JSONObject truck = trucks.getJSONObject(i);
                    JSONObject locateInfo = truck.getJSONObject("locateInfo");
                    KwfTruckGpsVo truckGps = new KwfTruckGpsVo();
                    truckGps.setTruckNo(truck.getString("vehicleNo"));
                    truckGps.setLat(locateInfo.getString("lat"));
                    truckGps.setLng(locateInfo.getString("lng"));
                    truckGps.setSpeed(locateInfo.getDouble("speed"));
                    truckGps.setGpsTime(locateInfo.getString("createTime"));
                    truckGps.setRunStatus(runStatus(truckGps.getGpsTime(), truckGps.getSpeed()));
                    truckGpsMap.put(truckGps.getTruckNo(), truckGps);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return truckGpsMap;
    }

    /**
     * @param params {truckNos 車牌號集, startTime 開始實際, endTime 結束時間}
     * @desc 车辆查询GPS(通过车牌号查询)
     * @author zk
     * @date 2023/9/27
     **/
    public List<KwfTruckGpsVo> queryLocateTrack(GpsByTruckNoDto params) {
        List<KwfTruckGpsVo>  truckGpsList = new ArrayList<>();
        long page = 1, pageSize = 1000, size = 0, pages = 0;
        Map queryParams = new HashMap<>(Global.NUMERICAL_SIXTEEN){{
            put("vehicleNo", params.getTruckNo());
            put("startTime", params.getStartTime());
            put("endTime", params.getEndTime());
            put("page", page);
            put("pageSize", pageSize);
        }};

        String httpResult = HttpClientUtil.post(queryLocateTrack, JSON.toJSONString(queryParams));
        if (StringUtils.isNotBlank(httpResult)) {
            JSONObject result = JSONObject.parseObject(httpResult);
            if (result.getInteger("code") != null && result.getInteger("code") != 200) {
                return truckGpsList;
            }
            JSONObject data = result.getJSONObject("data");
            if (data == null) {
                return truckGpsList;
            }
            size = data.getLong("size");
            pages = size/pageSize + (size%pageSize > 0 ? 1 : 0);
            JSONArray trucks = data.getJSONArray("list");
            for (int i=0; trucks != null && i < trucks.size(); i++) {
                JSONObject truck = trucks.getJSONObject(i);
                KwfTruckGpsVo truckGps = new KwfTruckGpsVo();
                truckGps.setLat(truck.getString("lat"));
                truckGps.setLng(truck.getString("lng"));
                truckGps.setSpeed(speed(truck.getString("speed")));
                truckGps.setGpsTime(truck.getString("createTime"));
                truckGps.setRunStatus(runStatus(truckGps.getGpsTime(), truckGps.getSpeed()));
                truckGpsList.add(truckGps);
            }

            if (pages <= 1) {
                return truckGpsList;
            }

            for (long i=2; i <= pages; i++) {
                queryParams.put("page", i);
                httpResult = HttpClientUtil.post(queryLocate, JSON.toJSONString(queryParams));
                if (StringUtils.isNotBlank(httpResult)) {
                    result = JSONObject.parseObject(httpResult);
                    if (result.getInteger("code") != null && result.getInteger("code") != 200) {
                        continue;
                    }
                    data = result.getJSONObject("data");
                    if (data == null) {
                        continue;
                    }
                    trucks = data.getJSONArray("list");
                    for (int j=0; trucks != null && j < trucks.size(); j++) {
                        JSONObject truck = trucks.getJSONObject(j);
                        KwfTruckGpsVo truckGps = new KwfTruckGpsVo();
                        truckGps.setTruckNo(truck.getString("vehicleNo"));
                        truckGps.setLat(truck.getString("lat"));
                        truckGps.setLng(truck.getString("lng"));
                        truckGps.setSpeed(speed(truck.getString("speed")));
                        truckGps.setGpsTime(truck.getString("createTime"));
                        truckGps.setRunStatus(runStatus(truckGps.getGpsTime(), truckGps.getSpeed()));
                        truckGpsList.add(truckGps);
                    }
                }
            }

        }
        return truckGpsList;
    }


    /**
     * @param truckNos 车牌号
     * @desc 查询车辆定位数据-单车牌号
     * @author zk
     * @date 2023/9/5
     **/
    public KwfTruckGpsVo findTruckLocate(String truckNo){
        if (StringUtils.isBlank(truckNo)) {
            return null;
        }

        try {
            Map<String, Object> params = new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
                put("vehicleNoList", new ArrayList<>(){{add(truckNo);}});
            }};
            String httpResult = HttpClientUtil.post(queryLocate, JSON.toJSONString(params));
            if (StringUtils.isNotBlank(httpResult)) {
                JSONObject result = JSONObject.parseObject(httpResult);
                if (result.getInteger("code") != null && result.getInteger("code") != 200) {
                    return null;
                }
                JSONArray trucks = result.getJSONArray("data");
                if (trucks != null && trucks.size() > 0) {
                    JSONObject truck = trucks.getJSONObject(Global.NUMERICAL_ZERO);
                    JSONObject locateInfo = truck.getJSONObject("locateInfo");
                    KwfTruckGpsVo truckGps = new KwfTruckGpsVo();
                    truckGps.setTruckNo(truck.getString("vehicleNo"));
                    truckGps.setLat(locateInfo.getString("lat"));
                    truckGps.setLng(locateInfo.getString("lng"));
                    truckGps.setSpeed(speed(locateInfo.getString("speed")));
                    truckGps.setGpsTime(locateInfo.getString("createTime"));
                    truckGps.setRunStatus(runStatus(truckGps.getGpsTime(), truckGps.getSpeed()));
                    return truckGps;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param gpsTimeStr 地位时间
     * @param speed 速度
     * @desc 校验当前车辆运行状态
     * @author zk
     * @date 2023/9/5
     **/
    public int runStatus(String gpsTimeStr, Double speed){
        if (StringUtils.isBlank(gpsTimeStr)) {
            return Global.NUMERICAL_TWO;
        }
        Date gpsTime = DateUtils.formatDate(gpsTimeStr);
        if (gpsTime == null) {
            return Global.NUMERICAL_TWO;
        }
        Date newTime = DateUtils.addDateMinutes(gpsTime, 15);
        int compareTo = DateUtils.compareTo(newTime, new Date());
        //-1 date1小于date2、0 date1等于date2、1 date1大于date2
        //运行状态(0行驶、1停止、2离线)
        return compareTo < 0 ? 2 : (speed == null || speed == 0) ? 1 : 0;
    }

    /**
     * @param obj 速度
     * @desc 速度处理
     * @author zk
     * @date 2023/9/5
     **/
    public static Double speed(String obj) {
        if (obj == null) {
            return Global.AMOUNT;
        }
        try {
            return Double.parseDouble(obj);
        } catch (Exception e) {
            log.error(e.getMessage());
            return Global.AMOUNT;
        }
    }

}
