package cn.iocoder.yudao.module.rescue.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.appBase.domain.SysAnnouncement;
import cn.iocoder.yudao.module.appBase.service.ISysAnnouncementService;
import cn.iocoder.yudao.module.constant.UserConstants;
import cn.iocoder.yudao.module.rescue.domain.*;
import cn.iocoder.yudao.module.rescue.dto.DriverInfo2Dto;
import cn.iocoder.yudao.module.rescue.dto.DriverInfoDto;
import cn.iocoder.yudao.module.rescue.dto.TaskDto;
import cn.iocoder.yudao.module.rescue.mapper.RescueInfoMapper;
import cn.iocoder.yudao.module.rescue.service.*;
import cn.iocoder.yudao.module.rescue.utils.DateUtils;
import cn.iocoder.yudao.module.rescue.utils.RedisUtil;
import cn.iocoder.yudao.module.rescue.utils.RedissonDelayQueue;
import cn.iocoder.yudao.module.rescue.utils.StringUtils;
import cn.iocoder.yudao.module.rescue.vo.BuckleVO;
import cn.iocoder.yudao.module.rescue.vo.MoneyManagement;
import cn.iocoder.yudao.module.rescue.vo.ReturnCarVO;
import cn.iocoder.yudao.module.staff.service.CompanyStaffService;
import cn.iocoder.yudao.module.staff.vo.CompanyStaffRespVO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.permission.dto.RoleReqDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.UserDTO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
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.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserDeptId;
import static cn.iocoder.yudao.module.rescue.service.impl.RescueDriverInfoServiceImpl.Redis_Driver_Key;
import static cn.iocoder.yudao.module.rescue.service.impl.RescueDriverInfoServiceImpl.Redis_Driver_Position_Key;
import static cn.iocoder.yudao.module.rescue.utils.DistanceCalculator.calculateTotalDistance;
import static cn.iocoder.yudao.module.rescue.utils.DistanceUtil.getDistance;
import static cn.iocoder.yudao.module.rescue.utils.DistanceUtil.getDistanceMeter;


/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author ruoyi
 * @date 2023-07-14
 */
@Service
public class RescueInfoServiceImpl extends ServiceImpl<RescueInfoMapper, RescueInfo> implements IRescueInfoService {
    @Resource
    private AdminUserApi userService;
    @Resource
    private IDriverInfoService driverInfoService;
    @Resource
    private IRescueDriverInfoService rescueDriverInfoService;
    @Resource
    @Lazy
    private RedisUtil redisCache2;
    @Resource
    private IRescueCarInfoService carInfoService;
    @Resource
    private IRescueInfoDetailService detailService;
    @Resource
    private DictDataApi dictDataService;
    @Resource
    private IRescueDriverPositionService positionService;
    @Resource
    private IRescueOrderInfoService rescueOrderInfoService;
    @Resource
    private IRescueDeptDriverService deptDriverService;
    @Resource
    private ISysAnnouncementService announcementService;
    @Resource
    private IRescueConfigService rescueConfigService;
    @Resource
    private IRescueRefuelRecordService refuelRecordService;
    @Resource
    private DeptApi deptService;
    @Resource
    private CompanyStaffService staffService;
    @Resource
    private RoleApi roleApi;
    @Resource
    private RedissonDelayQueue redissonDelayQueue;
    @Resource
    private IRescueDictStaffService rescueDictStaffService;
    @Resource
    @Lazy
    private IRescueInfoDetailService rescueInfoDetailService;


    /**
     * 查询【请填写功能名称】
     *
     * @param id 【请填写功能名称】主键
     * @return 【请填写功能名称】
     */
    @Override
    public RescueInfo selectRescueInfoById(Long id) {
        return baseMapper.selectById(id);
    }

    /**
     * 查询【请填写功能名称】列表
     *
     * @param rescueInfo 【请填写功能名称】
     * @return 【请填写功能名称】
     */
    @Override
    public IPage<RescueInfo> selectRescueInfoList(RescueInfo rescueInfo, Page<RescueInfo> page) {
        LoginUser user = getLoginUser();
        //当前用户创建的
        rescueInfo.setUserId(user.getId());
        AdminUserRespDTO user1 = userService.getUser(user.getId());
        //当前用户手机号的
        rescueInfo.setConnectionPhone(user1.getMobile());
        IPage<RescueInfo> rescueInfos = baseMapper.selectRescueInfoListApp(rescueInfo, page);

        for (RescueInfo info : rescueInfos.getRecords()) {
            String dljy_type = dictDataService.getDictDataLabel("dljy_type", info.getRescueType());
            info.setRescueTypeStr(dljy_type);
            String rescueStatus = dictDataService.getDictDataLabel("jy_status", info.getRescueStatus());
            info.setRescueStatusStr(rescueStatus);
            //获取当前司机的经纬度
            if (ObjectUtils.isNotEmpty(info.getDriverId())) {
                String driverKey = Redis_Driver_Key + info.getDeptId() + ":" + info.getDriverId();
                if (redisCache2.hasKey(driverKey)) {
                    JSONObject driverInfo = (JSONObject) JSONObject.parse(JSONObject.toJSONString(redisCache2.getCacheMap(driverKey)));
                    Double longitude = driverInfo.getDouble("longitude");
                    //纬度
                    Double latitude = driverInfo.getDouble("latitude");
                    Long distanceMeter = getDistanceMeter(Double.parseDouble(info.getRescueLongitude()), Double.parseDouble(info.getRescueLatitude()), longitude, latitude);
                    info.setDistance(Double.valueOf(distanceMeter * 1.3d).longValue());
                    info.setNeedTime(5 + (distanceMeter / 1000) * 2 + 5);
                }
            }
        }
        return rescueInfos;
    }

    @Override
    public IPage<RescueInfo> getKcList(RescueInfo rescueInfo, Page<RescueInfo> page) {
        Long deptId = getLoginUserDeptId();
        rescueInfo.setDeptId(deptId);
        IPage<RescueInfo> rescueInfos = baseMapper.getKcList(rescueInfo, page);
        return rescueInfos;
    }

    @Override
    public IPage<RescueInfo> getHcList(RescueInfo rescueInfo, Page<RescueInfo> page) {
        return null;
    }

    @Override
    public void openKc(Long rescueId) throws Exception {
        RescueInfo rescueInfo = this.getById(rescueId);
        if (!rescueInfo.getRescueStatus().equals("5")) {
            throw new Exception("救援尚未完成不可解扣");
        }
        DeptRespDTO sysDept = deptService.getDept(rescueInfo.getDeptId());
        LambdaUpdateWrapper<RescueInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(RescueInfo::getId, rescueId).set(RescueInfo::getRescueStatus, "6");
        this.update(wrapper);
        //增加详情
        detailService.save(new RescueInfoDetail(rescueId, "0", "解扣通知", "解扣通知"));
        //进行websocket通知
        //获取当前客户所在的调度中心
        List<String> deptIds = new ArrayList<>();
        deptIds.add(sysDept.getId().toString());
        for (String s : sysDept.getAncestors().split(",")) {
            deptIds.add(s);
        }

        List<AdminUserRespDTO> ddzxUsers = userService.getUsersByRoleRescue("ddzx", null, deptIds);
        //消息通知
        SysAnnouncement sysAnnouncement = new SysAnnouncement();
        sysAnnouncement.setType("解扣通知");
        sysAnnouncement.setToUserIds(ddzxUsers.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList()));
        sysAnnouncement.setTitle("解扣通知");
        sysAnnouncement.setContent("车牌号为：" + rescueInfo.getLicenseNum() + ",已经下发解扣通知");
        announcementService.insertSysAnnouncements2(sysAnnouncement);

        List<AdminUserRespDTO> qtUsers = userService.getUsersByRoleRescue("qt", null, deptIds);
        //消息通知
        SysAnnouncement sysAnnouncement2 = new SysAnnouncement();
        sysAnnouncement2.setType("解扣通知");
        sysAnnouncement2.setToUserIds(qtUsers.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList()));
        sysAnnouncement2.setTitle("解扣通知");
        sysAnnouncement2.setContent("车牌号为：" + rescueInfo.getLicenseNum() + ",已经下发解扣通知");
        announcementService.insertSysAnnouncements2(sysAnnouncement2);

        List<AdminUserRespDTO> kjUsers = userService.getUsersByRoleRescue("kj", null, deptIds);
        //消息通知
        SysAnnouncement sysAnnouncement3 = new SysAnnouncement();
        sysAnnouncement3.setType("解扣通知");
        sysAnnouncement3.setToUserIds(kjUsers.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList()));
        sysAnnouncement3.setTitle("解扣通知");
        sysAnnouncement3.setContent("车牌号为：" + rescueInfo.getLicenseNum() + ",已经下发解扣通知");
        announcementService.insertSysAnnouncements2(sysAnnouncement3);

        List<AdminUserRespDTO> cnUsers = userService.getUsersByRoleRescue("cn", null, deptIds);
        //消息通知
        SysAnnouncement sysAnnouncement4 = new SysAnnouncement();
        sysAnnouncement4.setType("解扣通知");
        sysAnnouncement4.setToUserIds(cnUsers.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList()));
        sysAnnouncement4.setTitle("解扣通知");
        sysAnnouncement4.setContent("车牌号为：" + rescueInfo.getLicenseNum() + ",已经下发解扣通知");
        announcementService.insertSysAnnouncements2(sysAnnouncement4);

    }

    @Override
    public IPage<RescueInfo> selectRescueInfoListByAdmin(RescueInfo rescueInfo, Page<RescueInfo> page) {
        LoginUser user = getLoginUser();
        AdminUserRespDTO adminUser = userService.getUser(user.getId());
        List<DeptRespDTO> childDeptList = deptService.getChildDeptList(adminUser.getDeptId());
        List<Long> deptList = childDeptList.stream().map(DeptRespDTO::getId).collect(Collectors.toList());
        deptList.add(adminUser.getDeptId());
        rescueInfo.setDeptList(deptList);

        IPage<RescueInfo> rescueInfos = baseMapper.selectRescueInfoList(rescueInfo, page);


        for (RescueInfo info : rescueInfos.getRecords()) {
            String dljy_type = dictDataService.getDictDataLabel("dljy_type", info.getRescueType());
            info.setRescueTypeStr(dljy_type);
            String rescueStatus = dictDataService.getDictDataLabel("jy_status", info.getRescueStatus());
            info.setRescueStatusStr(rescueStatus);
            //获取当前司机的经纬度
            if (ObjectUtils.isNotEmpty(info.getDriverId())) {
                //所在顶级机构

                String driverKey = Redis_Driver_Key + user.getTenantId() + ":" + info.getDriverId();
                if (redisCache2.hasKey(driverKey)) {
                    try {
                        JSONObject driverInfo = (JSONObject) JSONObject.parse(JSONObject.toJSONString(redisCache2.getCacheMap(driverKey)));
                        Double longitude = driverInfo.getDouble("longitude");
                        //纬度
                        Double latitude = driverInfo.getDouble("latitude");
                        Long distanceMeter = getDistanceMeter(Double.parseDouble(info.getRescueLongitude()), Double.parseDouble(info.getRescueLatitude()), longitude, latitude);
                        info.setDistance(Double.valueOf(distanceMeter * 1.3d).longValue());
                        info.setNeedTime(5 + (distanceMeter / 1000) * 2 + 5);
                    } catch (Exception ignored) {

                    }
                }
            }
        }
        return rescueInfos;
    }

    @Override
    public JSONObject rescueInfoDetail(Long rescueId) {
        JSONObject res = new JSONObject();
        RescueInfo rescueInfo = this.getById(rescueId);
        LambdaQueryWrapper<RescueOrderInfo> queryWrapperOrder = new LambdaQueryWrapper<>();
        queryWrapperOrder.eq(RescueOrderInfo::getRescueInfoId, rescueId).last("limit 1");
        RescueOrderInfo rescueOrderInfo = rescueOrderInfoService.getOne(queryWrapperOrder);
        if (ObjectUtils.isNotEmpty(rescueOrderInfo)) {
            rescueInfo.setOrderStatus(rescueOrderInfo.getOrderStatus());
            rescueInfo.setCommentDesc(rescueOrderInfo.getCommentDesc());
            rescueInfo.setCommentStar(rescueOrderInfo.getCommentStar());
        } else {
            rescueInfo.setOrderStatus("0");
        }
        res.put("rescueInfo", rescueInfo);
        //查询司机信息
        if (ObjectUtils.isNotEmpty(rescueInfo.getDriverId())) {
            DriverInfo driverInfo = driverInfoService.getById(rescueInfo.getDriverId());
            AdminUserRespDTO sysUser = userService.getUser(driverInfo.getUserId());
            driverInfo.setNickName(sysUser.getNickname());
            driverInfo.setRealName(sysUser.getNickname());
            driverInfo.setUserName(sysUser.getNickname());
            driverInfo.setAvatar(sysUser.getAvatar());
            res.put("driverInfo", driverInfo);
            //查询司机当前所在经纬度
            LambdaQueryWrapper<RescueDriverPosition> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RescueDriverPosition::getRescueInfoId, rescueId).eq(RescueDriverPosition::getDriverId, rescueInfo.getDriverId())
                    .orderByDesc(TenantBaseDO::getCreateTime).last("limit 1");
            RescueDriverPosition position = positionService.getOne(queryWrapper);
            res.put("driverPosition", position);
            res.put("setMoney", ObjectUtils.isEmpty(rescueOrderInfo.getSetMoney()) ? "" : rescueOrderInfo.getSetMoney());
        } else {
            res.put("driverInfo", "");
            res.put("driverPosition", "");
            res.put("setMoney", "");
        }
        //救援详细信息
        LambdaQueryWrapper<RescueInfoDetail> queryWrapper3 = new LambdaQueryWrapper<>();
        queryWrapper3.eq(RescueInfoDetail::getRescueInfoId, rescueId).orderByAsc(TenantBaseDO::getCreateTime);
        List<RescueInfoDetail> details = detailService.list(queryWrapper3);
        res.put("detail", details);
        return res;
    }

    @Override
    public IPage<RescueInfo> selectRescueListSystem(Page<RescueInfo> page, RescueInfo rescueInfo) {
        return baseMapper.selectPage(page,new QueryWrapper<>());
    }

    @Override
    public IPage<RescueInfo> selectRescueListSystem2(RescueInfo rescueInfo, Page<RescueInfo> page) {
        return baseMapper.selectRescueListSystem2(rescueInfo, page);
    }

    @Override
    public JSONObject listData(RescueInfo rescueInfo) {
        rescueInfo.setFlag("1");
        Double rescueTcBig = 0d;
        Double rescueTcMid = 0d;
        Double rescueTcSmall = 0d;
        RescueConfig rescueConfig = rescueConfigService.selectRescueConfigByDeptId();
        if (ObjectUtils.isNotEmpty(rescueConfig)) {
            rescueTcBig = Optional.ofNullable(rescueConfig.getRescueTcBig()).orElse(0d);
            rescueTcMid = Optional.ofNullable(rescueConfig.getRescueTcMid()).orElse(0d);
            rescueTcSmall = Optional.ofNullable(rescueConfig.getRescueTcSmall()).orElse(0d);
        }
        rescueInfo.setRescueTcBig(rescueTcBig);
        rescueInfo.setRescueTcMid(rescueTcMid);
        rescueInfo.setRescueTcSmall(rescueTcSmall);
        JSONObject res = baseMapper.listData(rescueInfo);
        //在计算燃油费
        JSONObject jsonObject = refuelRecordService.listData(rescueInfo);
        res.put("refuelMoney", jsonObject.get("refuelMoney"));
        return res;
    }

    @Override
    public void designateDriver(Long rescueId, Long driverId) throws Exception {
        //判断当前订单是够已经开始
        RescueInfo rescueInfo = getById(rescueId);
        if (ObjectUtils.isNotEmpty(rescueInfo.getDriverId())) {
            throw new Exception("当前订单已经开始");
        }
        //判断当前司机 是否已经被指派过当前订单
        LambdaQueryWrapper<RescueDriverInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RescueDriverInfo::getDriverId, driverId).eq(RescueDriverInfo::getRescueId, rescueId)
                .eq(RescueDriverInfo::getDriverAccept, "2").last("limit 1");
        RescueDriverInfo driverInfo = rescueDriverInfoService.getOne(queryWrapper);
        if (!ObjectUtils.isEmpty(driverInfo)) {
            throw new Exception("已指派,请勿重复指派");
        }
        RescueDriverInfo rescueDriverInfo = new RescueDriverInfo();
        rescueDriverInfo.setDriverId(driverId);
        rescueDriverInfo.setRescueId(rescueId);
        rescueDriverInfo.setDriverAccept("2");
        rescueDriverInfoService.insertRescueDriverInfo(rescueDriverInfo);
        //指派成功之后 1进行app应用通知 2电话通知
        //消息通知
        DriverInfo tempDriver = driverInfoService.getById(driverId);
        SysAnnouncement sysAnnouncement = new SysAnnouncement();
        sysAnnouncement.setType("救援信息");
        sysAnnouncement.setToUserIds(Collections.singletonList(tempDriver.getUserId()));
        sysAnnouncement.setTitle("有新的救援订单请立即处理");
        sysAnnouncement.setContent("有新的救援订单请立即处理");
        announcementService.insertSysAnnouncements(sysAnnouncement);

        // 删除延时消息
        redissonDelayQueue.removeAllTasks(rescueId);
    }


    /**
     * 新增【请填写功能名称】
     *
     * @param rescueInfo 【请填写功能名称】
     * @return 结果
     */
    @Override
    @DSTransactional
    public void insertRescueInfo(RescueInfo rescueInfo) {
        // 获取当前的用户
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        // 获取当前的用户的部门ID
        AdminUserRespDTO user = userService.getUser(loginUser.getId());

        rescueInfo.setUserId(loginUser.getId());
        rescueInfo.setRescueTime(new Date());
        rescueInfo.setDeptId(user.getDeptId());
        //数据新增
        if (rescueInfo.getIsAppointment().equals("1")) {
            //如果是预约单子
            rescueInfo.setRescueStatus("1");
            baseMapper.insert(rescueInfo);
            detailService.save(new RescueInfoDetail(rescueInfo.getId(), "0", "预约救援", "预约救援"));
        } else {
            rescueInfo.setRescueStatus("2");
            rescueInfo.setRescueTime(new Date());
            baseMapper.insert(rescueInfo);
            detailService.save(new RescueInfoDetail(rescueInfo.getId(), "0", "救援发起", "救援发起"));

            // TODO 暂时注掉 后面在看要不要完善
//            // 自动通知对应路段司机
//            List<RescueDictStaff> list = rescueDictStaffService.list(new LambdaQueryWrapper<RescueDictStaff>().in(RescueDictStaff::getDictId, rescueInfo.getRoadIds()));
//            if (CollectionUtil.isEmpty(list)) {
//                throw exception0(500, "该路段没有司机，请先配置");
//            }
//            // 司机的userId
//            Set<Long> driverIds = list.stream()
//                    .map(RescueDictStaff::getDriverIds)
//                    .flatMap(item -> Arrays.stream(item.split(",")))
//                    .map(Long::parseLong)
//                    .collect(Collectors.toSet());
//            // 司机的driver_id
//            List<DriverInfo> driverInfos = driverInfoService.list(new LambdaQueryWrapper<DriverInfo>().in(DriverInfo::getUserId, driverIds));
//            driverInfos.forEach(item -> {
//                // 发消息
//                SysAnnouncement sysAnnouncement = new SysAnnouncement();
//                sysAnnouncement.setType("救援信息");
//                sysAnnouncement.setToUserIds(Collections.singletonList(item.getUserId()));
//                sysAnnouncement.setTitle("有新的救援订单请立即处理");
//                sysAnnouncement.setContent("有新的救援订单请立即处理");
//                announcementService.insertSysAnnouncements(sysAnnouncement);
//                // 发订单
//                RescueDriverInfo rescueDriverInfo = new RescueDriverInfo();
//                rescueDriverInfo.setDriverId(item.getId());
//                rescueDriverInfo.setRescueId(rescueInfo.getId());
//                rescueDriverInfo.setDriverAccept("2");
//                rescueDriverInfoService.insertRescueDriverInfo(rescueDriverInfo);
//            });
//            // 新增延迟消息，用于三分钟后没人接单通知
//            TaskDto taskDto = new TaskDto();
//            taskDto.setManageId(loginUser.getId());
//            taskDto.setRescueInfoId(rescueInfo.getId());
//            redissonDelayQueue.offerTask(JSON.toJSONString(taskDto), UserConstants.RESCUE_TIME);
        }

    }

    /**
     * 修改【请填写功能名称】
     *
     * @param rescueInfo 【请填写功能名称】
     * @return 结果
     */
    @Override
    public int updateRescueInfo(RescueInfo rescueInfo) {
        if (rescueInfo.getRescueStatus().compareTo("9") > 0) {
            rescueInfo.setRescueStatus(null);
        }
        // 取消订单时删除定时任务
        if (null != rescueInfo && StringUtils.isNotEmpty(rescueInfo.getRescueStatus()) && rescueInfo.getRescueStatus().equals("0")) {
            redissonDelayQueue.removeAllTasks(rescueInfo.getId());
        }
        return baseMapper.updateById(rescueInfo);
    }

    /**
     * 批量删除【请填写功能名称】
     *
     * @param ids 需要删除的【请填写功能名称】主键
     * @return 结果
     */
    @Override
    public int deleteRescueInfoByIds(Long[] ids) {
        return baseMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除【请填写功能名称】信息
     *
     * @param id 【请填写功能名称】主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRescueInfoById(Long id) {
        //主表删除
        baseMapper.deleteById(id);
        //删除其余子表
        baseMapper.deleteOtherInfo1(id);
        baseMapper.deleteOtherInfo2(id);
    }

    @Override
    public IPage<DriverInfo> driverList(DriverInfoDto driverInfo, Page<DriverInfo> page) {
        IPage<DriverInfo> driverInfos = baseMapper.driverList(driverInfo, page);
        for (DriverInfo info : driverInfos.getRecords()) {
            LambdaQueryWrapper<RescueCarInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RescueCarInfo::getCarOwn, "1").eq(RescueCarInfo::getPossessorId, info.getId());
            List<RescueCarInfo> list = carInfoService.list(queryWrapper);
            if (CollectionUtil.isNotEmpty(list)) {
                info.setCarInfoList(list);
            } else {
                info.setCarInfoList(new ArrayList<>());
            }

        }
        return driverInfos;
    }

    @Override
    public DriverInfo getDriverById(Long driverId) {
        DriverInfo driverInfo = driverInfoService.getById(driverId);
        AdminUserRespDTO user = userService.getUser(driverInfo.getUserId());
        driverInfo.setRealName(user.getNickname());
        driverInfo.setAvatar(user.getAvatar());
        driverInfo.setSex(user.getSex().toString());
        driverInfo.setUserAge(35);
        driverInfo.setUserName(user.getNickname());
        driverInfo.setNickName(user.getNickname());
        return null;
    }

    @Override
    @Transactional
    public void addDriver(DriverInfo driverInfoDto) throws Exception {
        LambdaQueryWrapper<DriverInfo> queryWrapperD = new LambdaQueryWrapper<>();
        queryWrapperD.eq(DriverInfo::getPhonenumber, driverInfoDto.getPhonenumber());
        List<DriverInfo> list = driverInfoService.list(queryWrapperD);
        if (!CollectionUtil.isEmpty(list)) {
            throw new Exception("该手机号已绑定司机，请不要重复添加");
        }
        AdminUserRespDTO sysUser = userService.getUserByMobile(driverInfoDto.getPhonenumber());
        driverInfoDto.setAuthStatus("2");
        if (!ObjectUtils.isEmpty(sysUser)) {
            DriverInfo driverInfoQuery = new DriverInfo();
            driverInfoQuery.setUserId(sysUser.getId());
            List<DriverInfo> driverInfos = driverInfoService.selectDriverInfoList(driverInfoQuery);
            if (CollectionUtil.isEmpty(driverInfos)) {
                UserDTO newUser = new UserDTO();
                newUser.setNickname(driverInfoDto.getRealName());
                newUser.setSex(driverInfoDto.getSex());
                newUser.setAvatar(driverInfoDto.getAvatar());
                newUser.setDeptId(driverInfoDto.getDeptId());
                userService.createUser(newUser);
                //代表为救援司机角色 需要添加到司机表中
                driverInfoDto.setUserId(newUser.getId());
                driverInfoDto.setDriverStatus("4");
                driverInfoService.save(driverInfoDto);
            }
        } else {
            // 新增用户信息
            CompanyStaffRespVO staffRespVO = new CompanyStaffRespVO();
            staffRespVO.setLoginAccount(driverInfoDto.getPhonenumber());
            staffRespVO.setPassword("123456");
            RoleReqDTO roleReqDTO = roleApi.getRoleInfo("jysj");
            List<Long> roleIds = new ArrayList<>();
            roleIds.add((roleReqDTO.getId()));
            staffRespVO.setRoleIds(roleIds);
            staffRespVO.setName(driverInfoDto.getRealName());
            staffRespVO.setSex(driverInfoDto.getSex());
            staffRespVO.setTel(driverInfoDto.getPhonenumber());
            Long userId = staffService.saveStaff(staffRespVO);
            //代表为救援司机角色 需要添加到司机表中
            driverInfoDto.setUserId(userId);
            driverInfoDto.setDriverStatus("4");
            driverInfoService.save(driverInfoDto);
        }
        //处理车辆信息
        if (!CollectionUtil.isEmpty(driverInfoDto.getCarInfoList())) {
            for (RescueCarInfo rescueCarInfo : driverInfoDto.getCarInfoList()) {
                String rescueCarNum = rescueCarInfo.getRescueCarNum();
                LambdaQueryWrapper<RescueCarInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(RescueCarInfo::getRescueCarNum, rescueCarNum);
                RescueCarInfo one = carInfoService.getOne(queryWrapper);
                if (ObjectUtils.isNotEmpty(one)) {
                    rescueCarInfo.setCarOwn("1");
                    rescueCarInfo.setPossessorId(driverInfoDto.getId());
                    rescueCarInfo.setId(one.getId());
                    carInfoService.updateById(rescueCarInfo);
                } else {
                    rescueCarInfo.setCarOwn("1");
                    rescueCarInfo.setPossessorId(driverInfoDto.getId());
                    carInfoService.save(rescueCarInfo);
                }
            }

        }


    }

    @Override
    @Transactional
    public void updateDriver(DriverInfo driverInfoDto) {
        driverInfoService.updateDriverInfo(driverInfoDto);
        LambdaQueryWrapper<RescueCarInfo> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(RescueCarInfo::getPossessorId, driverInfoDto.getId()).eq(RescueCarInfo::getCarOwn, "1");
        carInfoService.remove(queryWrapper1);
        //处理车辆信息
        if (!CollectionUtil.isEmpty(driverInfoDto.getCarInfoList())) {
            for (RescueCarInfo rescueCarInfo : driverInfoDto.getCarInfoList()) {
                String rescueCarNum = rescueCarInfo.getRescueCarNum();
                LambdaQueryWrapper<RescueCarInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(RescueCarInfo::getRescueCarNum, rescueCarNum);
                RescueCarInfo one = carInfoService.getOne(queryWrapper);
                if (ObjectUtils.isNotEmpty(one)) {
                    rescueCarInfo.setCarOwn("1");
                    rescueCarInfo.setPossessorId(driverInfoDto.getId());
                    rescueCarInfo.setId(one.getId());
                    carInfoService.updateById(rescueCarInfo);
                } else {
                    rescueCarInfo.setCarOwn("1");
                    rescueCarInfo.setPossessorId(driverInfoDto.getId());
                    carInfoService.save(rescueCarInfo);
                }
            }

        }
    }

    @Override
    @Transactional
    public void delDriver(Long[] ids) {
        for (Long id : ids) {
            DriverInfo driverInfo = driverInfoService.selectDriverInfoById(id);
            Long userId = driverInfo.getUserId();
            staffService.deleteStaffByUserId(userId);
            driverInfoService.removeById(id);
            LambdaQueryWrapper<RescueCarInfo> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(RescueCarInfo::getPossessorId, id).eq(RescueCarInfo::getCarOwn, "1");
            carInfoService.remove(queryWrapper1);
        }
    }

    @Override
    public List<DriverInfo2Dto> driverListApp(DriverInfoDto driverInfoDto) {
        //当前登录用户
        LoginUser loginUser = getLoginUser();
        List<DriverInfo2Dto> dtos = baseMapper.driverListApp(driverInfoDto);
        //处理其余信息
        //获取司机所在经纬度
        for (DriverInfo2Dto dto : dtos) {
            String redisKey2 = Redis_Driver_Key + loginUser.getTenantId() + ":" + dto.getId();
            if (redisCache2.hasKey(redisKey2)) {
                Map<String, Object> cacheMap = redisCache2.getCacheMap(redisKey2);
                dto.setDriverLatitude(cacheMap.get("latitude").toString());
                dto.setDriverLongitude(cacheMap.get("longitude").toString());
                dto.setDriverPositionInfo(cacheMap.get("positionInfo").toString());
                dto.setDriverStatus(cacheMap.get("status").toString());
            } else {
                dto.setDriverStatus("4");
            }
        }
        return dtos;
    }

    //获取司机在地图上的位置分布
    @Override
    public List<DriverInfo2Dto> driverInMap(DriverInfoDto driverInfoDto) {
        //当前登录用户
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        List<DriverInfo2Dto> dtos = baseMapper.driverListApp(driverInfoDto);
        //处理其余信息
        //获取司机所在经纬度
        int i = 1;
        for (DriverInfo2Dto dto : dtos) {
            String redisKey2 = Redis_Driver_Key + loginUser.getTenantId() + ":" + dto.getId();
            if (redisCache2.hasKey(redisKey2)) {
                try {
                    Map<String, Object> cacheMap = redisCache2.getCacheMap(redisKey2);
                    dto.setDriverLatitude(cacheMap.get("latitude").toString());
                    dto.setDriverLongitude(cacheMap.get("longitude").toString());
                    dto.setDriverPositionInfo(cacheMap.get("positionInfo").toString());
                    dto.setDriverStatus(cacheMap.get("status").toString());
                } catch (Exception ignored) {

                }

            } else {
                dto.setDriverStatus("4");
            }
            dto.setCarImage("https://www.nuoyunr.com/lananRsc/rescue/car" + i + ".png");
            if (i >= 4) {
                i = 1;
            } else {
                i++;
            }
        }
        return dtos;
    }

    @Override
    public Map<String, Integer> driverInMap2() {
        return baseMapper.driverInMap2();
    }

    @Override
    public void dealOverTimeRescue() {
        baseMapper.dealOverTimeRescue();
        //获取
        List<RescueInfo> overTimeRescue = baseMapper.getOverTimeRescue();
        List<Long> userIds = new ArrayList<>();
        //给下一级 进行分配
        for (RescueInfo rescueInfo : overTimeRescue) {
            if (StringUtils.isEmpty(rescueInfo.getDriverLevel())) continue;
            LambdaQueryWrapper<RescueDeptDriver> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RescueDeptDriver::getDeptId, rescueInfo.getId());
            RescueDeptDriver rescueDeptDriver = deptDriverService.getOne(queryWrapper);
            if (rescueInfo.getDriverLevel().equals("1")) {
                if (StringUtils.isNotEmpty(rescueDeptDriver.getFirstDriverIds())) {
                    String[] driverIds = rescueDeptDriver.getSecondDriverIds().split(",");
                    for (String driverId : driverIds) {
                        //此时找到了合适的司机进行任务的指派
                        RescueDriverInfo rescueDriverInfo = new RescueDriverInfo();
                        rescueDriverInfo.setDriverId(Long.parseLong(driverId));
                        rescueDriverInfo.setRescueId(rescueInfo.getId());
                        rescueDriverInfo.setDriverAccept("2");
                        rescueDriverInfo.setDriverLevel("2");
                        rescueDriverInfoService.insertRescueDriverInfo(rescueDriverInfo);
                        DriverInfo driverInfo = driverInfoService.getById(driverId);
                        userIds.add(driverInfo.getUserId());
                    }
                }

            } else if (rescueInfo.getDriverLevel().equals("2")) {
                if (StringUtils.isNotEmpty(rescueDeptDriver.getFirstDriverIds())) {
                    String[] driverIds = rescueDeptDriver.getSecondDriverIds().split(",");
                    for (String driverId : driverIds) {
                        //此时找到了合适的司机进行任务的指派
                        RescueDriverInfo rescueDriverInfo = new RescueDriverInfo();
                        rescueDriverInfo.setDriverId(Long.parseLong(driverId));
                        rescueDriverInfo.setRescueId(rescueInfo.getId());
                        rescueDriverInfo.setDriverAccept("2");
                        rescueDriverInfo.setDriverLevel("3");
                        rescueDriverInfoService.insertRescueDriverInfo(rescueDriverInfo);
                        DriverInfo driverInfo = driverInfoService.getById(driverId);
                        userIds.add(driverInfo.getUserId());
                    }
                }
            }
        }
        //消息通知
        SysAnnouncement sysAnnouncement = new SysAnnouncement();
        sysAnnouncement.setType("救援信息");
        sysAnnouncement.setToUserIds(userIds);
        sysAnnouncement.setTitle("有新的救援订单请立即处理");
        sysAnnouncement.setContent("有新的救援订单请立即处理");
        announcementService.insertSysAnnouncements(sysAnnouncement);
    }

    //指派司机
    @Override
    public void appointDriver(Long deptId, Long rescueId, String longitude, String latitude) {
        //省：市：区
        String redisKey = Redis_Driver_Position_Key + deptId;
        Map<String, Object> cacheMap = redisCache2.getCacheMap(redisKey);
        List<Object> cacheList = new ArrayList<>();
        cacheMap.forEach((key, value) -> cacheList.add(value));
        if (!CollectionUtil.isEmpty(cacheList)) {
            //获取之前拒绝过得司机
            LambdaQueryWrapper<RescueDriverInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(RescueDriverInfo::getRescueId, rescueId).eq(RescueDriverInfo::getDriverAccept, "0");
            List<RescueDriverInfo> rejectDrivers = rescueDriverInfoService.list(queryWrapper);
            List<Long> rejectDriverIds = new ArrayList<>();
            if (!CollectionUtil.isEmpty(rejectDrivers)) {
                rejectDriverIds = rejectDrivers.stream().map(RescueDriverInfo::getDriverId).collect(Collectors.toList());
            }
            //如果存在司机
            List<JSONObject> driverList = JSONArray.parseArray(JSONArray.toJSONString(cacheList), JSONObject.class);
            List<Long> finalRejectDriverIds = rejectDriverIds;
            driverList = driverList.stream().filter(it -> {
                boolean flag = true;
                String driverKey = Redis_Driver_Key + deptId + ":" + it.getString("driverId");
                if (!redisCache2.hasKey(driverKey)) {
                    return false;
                }
                JSONObject driverInfo = (JSONObject) JSONObject.parse(JSONObject.toJSONString(redisCache2.getCacheMap(driverKey)));
                //判断司机是否在线且空闲
                flag = driverInfo.getInteger("status") == 1;
                if (finalRejectDriverIds.contains(Long.parseLong(it.getString("driverId")))) {
                    flag = false;
                }
                return flag;
            }).sorted((o1, o2) -> {
                //经度
                Double longitudeO1 = o1.getDouble("longitude");
                //纬度
                Double latitudeO1 = o2.getDouble("latitude");
                //经度
                Double longitudeO2 = o2.getDouble("longitude");
                //纬度
                Double latitudeO2 = o2.getDouble("latitude");
                //距离1
                Double distance1 = getDistance(longitudeO1, latitudeO1, Double.parseDouble(longitude), Double.parseDouble(latitude));
                //距离2
                Double distance2 = getDistance(longitudeO2, latitudeO2, Double.parseDouble(longitude), Double.parseDouble(latitude));
                return distance2 > distance1 ? 1 : 0;
            }).collect(Collectors.toList());


            if (!CollectionUtil.isEmpty(driverList)) {
                JSONObject selectDriver = driverList.get(0);
                //此时找到了合适的司机进行任务的指派
                RescueDriverInfo rescueDriverInfo = new RescueDriverInfo();
                rescueDriverInfo.setDriverId(selectDriver.getLong("driverId"));
                rescueDriverInfo.setRescueId(rescueId);
                rescueDriverInfo.setDriverAccept("2");
                rescueDriverInfoService.insertRescueDriverInfo(rescueDriverInfo);
            }
        }
        detailService.save(new RescueInfoDetail(rescueId, "0", "等待司机响应", "等待司机响应"));
    }

    @Override
    public Map<String, Object> getRescueStatistics(RescueInfo rescueInfo) {
        LoginUser loginUser = getLoginUser();
        AdminUserRespDTO user = userService.getUser(loginUser.getId());
        //当前用户创建的
        rescueInfo.setUserId(loginUser.getId());
        //当前用户手机号的
        rescueInfo.setConnectionPhone(user.getMobile());
        Map<String, Object> res = baseMapper.getRescueStatistics(rescueInfo);
        return res;
    }

    @Override
    public Map<String, Object> getRescueStatisticsByAdmin(RescueInfo rescueInfo) {
        LoginUser user = getLoginUser();
        AdminUserRespDTO adminUser = userService.getUser(user.getId());
        List<DeptRespDTO> childDeptList = deptService.getChildDeptList(adminUser.getDeptId());
        List<Long> deptList = childDeptList.stream().map(DeptRespDTO::getId).collect(Collectors.toList());
        deptList.add(adminUser.getDeptId());
        rescueInfo.setDeptList(deptList);
        Map<String, Object> res = baseMapper.getRescueStatisticsByAdmin(rescueInfo);

        return res;
    }

    @Override
    public void trajectoryJs(Long rescueId) throws Exception {
        RescueInfo rescueInfo = this.getById(rescueId);
        if (Integer.parseInt(rescueInfo.getRescueStatus()) < 5) {
            throw new Exception("救援尚未结束请稍等");
        }
        LambdaQueryWrapper<RescueDriverPosition> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RescueDriverPosition::getRescueInfoId, rescueId).orderByAsc(TenantBaseDO::getCreateTime);
        List<RescueDriverPosition> list = positionService.list(queryWrapper);
        double totalDistance = 0d;
        if (CollectionUtil.isNotEmpty(list) && list.size() > 1) {
            List<Double> latitudes = list.stream().map(it -> {
                return Double.parseDouble(it.getLatitude());
            }).collect(Collectors.toList());
            List<Double> longitudes = list.stream().map(it -> {
                return Double.parseDouble(it.getLongitude());
            }).collect(Collectors.toList());
            totalDistance = calculateTotalDistance(latitudes, longitudes);

        }
        rescueInfo.setRescueDistance(totalDistance * 1.5d);
        this.updateById(rescueInfo);

    }


    //指派司机
    public void appointDriverByBusiness(Long deptId, Long rescueId) {
        //根据部门主键获取  第一梯队的司机
        RescueDeptDriver rescueDeptDriver = new RescueDeptDriver();
        rescueDeptDriver.setDeptId(deptId);
        List<RescueDeptDriver> rescueDeptDrivers = deptDriverService.selectRescueDeptDriverList(rescueDeptDriver);
        if (CollectionUtil.isEmpty(rescueDeptDrivers) || StringUtils.isEmpty(rescueDeptDrivers.get(0).getFirstDriverIds())) {
            return;
        }
        String[] driverIds = rescueDeptDrivers.get(0).getFirstDriverIds().split(",");
        List<Long> userIds = new ArrayList<>();
        for (String driverId : driverIds) {
            //此时找到了合适的司机进行任务的指派
            RescueDriverInfo rescueDriverInfo = new RescueDriverInfo();
            rescueDriverInfo.setDriverId(Long.parseLong(driverId));
            rescueDriverInfo.setRescueId(rescueId);
            rescueDriverInfo.setDriverAccept("2");
            rescueDriverInfo.setDriverLevel("1");
            rescueDriverInfoService.insertRescueDriverInfo(rescueDriverInfo);
            DriverInfo driverInfo = driverInfoService.getById(driverId);
            userIds.add(driverInfo.getUserId());
        }
        //消息通知
        SysAnnouncement sysAnnouncement = new SysAnnouncement();
        sysAnnouncement.setType("救援信息");
        sysAnnouncement.setToUserIds(userIds);
        sysAnnouncement.setTitle("有新的救援订单请立即处理");
        sysAnnouncement.setContent("有新的救援订单请立即处理");
        announcementService.insertSysAnnouncements(sysAnnouncement);
    }

    @Override
    public IPage<RescueInfo> getRescueInfoByDriver(RescueInfo rescueInfo, Page<RescueInfo> page) {
        return baseMapper.getRescueInfoByDriver(rescueInfo, page);
    }

    public List<MoneyManagement> moneyManagement2(List<RescueInfo> rescueInfos, String rescueStart) {
        List<MoneyManagement> resList = new ArrayList<>();
        Double rescueTcBig = 0d;
        Double rescueTcMid = 0d;
        Double rescueTcSmall = 0d;
        RescueConfig rescueConfig = rescueConfigService.selectRescueConfigByDeptId();
        if (ObjectUtils.isNotEmpty(rescueConfig)) {
            rescueTcBig = Optional.ofNullable(rescueConfig.getRescueTcBig()).orElse(0d);
            rescueTcMid = Optional.ofNullable(rescueConfig.getRescueTcMid()).orElse(0d);
            rescueTcSmall = Optional.ofNullable(rescueConfig.getRescueTcSmall()).orElse(0d);
        }
        for (RescueInfo info : rescueInfos) {
            MoneyManagement moneyManagement = new MoneyManagement();
            moneyManagement.setDriverName(info.getDriverName());
            Double grossWages = 0d;
            Double tempSetMoney = ObjectUtils.isNotEmpty(info.getSetMoney()) ? Double.valueOf(info.getSetMoney()) / 100d : 0d;
            Double tempCheckpointMoney = ObjectUtils.isNotEmpty(info.getCheckpointMoney()) ? info.getCheckpointMoney() : 0d;
            JSONObject monthRescueRefuelRecord = new JSONObject();
            monthRescueRefuelRecord.put("refuelMoney", 0);
            monthRescueRefuelRecord.put("refuelNum", 0);
            monthRescueRefuelRecord.put("refuelDistance", 0);
            try {
                LambdaQueryWrapper<RescueCarInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(RescueCarInfo::getRescueCarNum, info.getDriverCarNum()).last("limit 1");
                RescueCarInfo carInfo = carInfoService.getOne(queryWrapper);
                monthRescueRefuelRecord = refuelRecordService.getMonthRescueRefuelRecord(info.getDriverId(), DateUtil.format(info.getRescueTime(), "yyyy-MM"), carInfo.getId());
            } catch (Exception ignored) {
            }
            moneyManagement.setLicenseNum(info.getLicenseNum());
            moneyManagement.setFeeType(info.getFeeType());
            moneyManagement.setRescueTime(info.getRescueTime());
            moneyManagement.setDiverCarNum(info.getDriverCarNum());
            moneyManagement.setSetMoney(tempSetMoney);
            moneyManagement.setCheckpointMoney(info.getCheckpointMoney());
            moneyManagement.setUpMoney(tempSetMoney - tempCheckpointMoney);
            moneyManagement.setEmptyingDistance(info.getEmptyNum());
            String carType = "3";
            if (StringUtils.isNotEmpty(info.getDriverCarNum())) {
                RescueCarInfo carInfo = carInfoService.selectRescueCarInfoByNum(info.getDriverCarNum());
                carType = carInfo.getRescueCarType();
            }

            if (carType.equals("1")) {
                //大车
                moneyManagement.setRoyaltyRatio(rescueTcBig);
                moneyManagement.setRoyaltyMoney(tempSetMoney * rescueTcBig);
            } else if (carType.equals("2")) {
                //中车
                moneyManagement.setRoyaltyRatio(rescueTcMid);
                moneyManagement.setRoyaltyMoney(tempSetMoney * rescueTcMid);
            } else {
                //小车
                moneyManagement.setRoyaltyRatio(rescueTcSmall);
                moneyManagement.setRoyaltyMoney(tempSetMoney * rescueTcSmall);
            }
            //获取当前车 当前驾驶员 这个月跑了几次
            JSONObject driverInfoObj = baseMapper.getDriverCarNum(info.getDriverId(), info.getDriverCarNum(), rescueStart);
            //计算平均燃油费和平均油耗
            Double avgFuelConsumption = 0d;
            Double mglYh = 0d;
            if (driverInfoObj.getInteger("allNum") != 0) {
                avgFuelConsumption = monthRescueRefuelRecord.getDouble("refuelMoney") / driverInfoObj.getInteger("allNum");
                mglYh = monthRescueRefuelRecord.getDouble("refuelNum") / driverInfoObj.getDouble("allDistance");
            }
            moneyManagement.setFuelCost(avgFuelConsumption);
            moneyManagement.setOilConsumption(mglYh);
            Double oilSubsidy = Optional.ofNullable(info.getEmptyNum()).orElse(0d) * mglYh;
            moneyManagement.setOilSubsidy(oilSubsidy);
            grossWages = grossWages + moneyManagement.getRoyaltyMoney() + oilSubsidy - avgFuelConsumption;
            moneyManagement.setGrossWages(grossWages);
            resList.add(moneyManagement);
        }

        return resList;
    }

    /**
     * 有问题
     */
    @Deprecated
    public List<MoneyManagement> moneyManagement(RescueInfo rescueInfo) {
        List<MoneyManagement> resList = new ArrayList<>();
        Double rescueTcBig = 0d;
        Double rescueTcMid = 0d;
        Double rescueTcSmall = 0d;
        RescueConfig rescueConfig = rescueConfigService.selectRescueConfigByDeptId();
        if (ObjectUtils.isNotEmpty(rescueConfig)) {
            rescueTcBig = Optional.ofNullable(rescueConfig.getRescueTcBig()).orElse(0d);
            rescueTcMid = Optional.ofNullable(rescueConfig.getRescueTcMid()).orElse(0d);
            rescueTcSmall = Optional.ofNullable(rescueConfig.getRescueTcSmall()).orElse(0d);
        }
        Integer pageNo = 1;
        while (true) {
            Page<RescueInfo> page = new Page<>(pageNo, 500);
            IPage<RescueInfo> rescueInfos = baseMapper.getRescueInfoByDriver(rescueInfo, page);
            if (ObjectUtil.isEmpty(rescueInfos) && rescueInfos.getRecords().isEmpty()) {
                break;
            }
            for (RescueInfo info : rescueInfos.getRecords()) {
                MoneyManagement moneyManagement = new MoneyManagement();
                moneyManagement.setDriverName(info.getDriverName());
                Double grossWages = 0d;
                Double tempSetMoney = ObjectUtils.isNotEmpty(info.getSetMoney()) ? Double.valueOf(info.getSetMoney()) / 100d : 0d;
                Double tempCheckpointMoney = ObjectUtils.isNotEmpty(info.getCheckpointMoney()) ? info.getCheckpointMoney() : 0d;
                JSONObject monthRescueRefuelRecord = new JSONObject();
                monthRescueRefuelRecord.put("refuelMoney", 0);
                monthRescueRefuelRecord.put("refuelNum", 0);
                monthRescueRefuelRecord.put("refuelDistance", 0);
                try {
                    LambdaQueryWrapper<RescueCarInfo> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(RescueCarInfo::getRescueCarNum, info.getDriverCarNum()).last("limit 1");
                    RescueCarInfo carInfo = carInfoService.getOne(queryWrapper);
                    monthRescueRefuelRecord = refuelRecordService.getMonthRescueRefuelRecord(info.getDriverId(), DateUtil.format(info.getRescueTime(), "yyyy-MM"), carInfo.getId());
                } catch (Exception ignored) {
                }
                moneyManagement.setLicenseNum(info.getLicenseNum());
                moneyManagement.setFeeType(info.getFeeType());
                moneyManagement.setRescueTime(info.getRescueTime());
                moneyManagement.setDiverCarNum(info.getDriverCarNum());
                moneyManagement.setSetMoney(tempSetMoney);
                moneyManagement.setCheckpointMoney(info.getCheckpointMoney());
                moneyManagement.setUpMoney(tempSetMoney - tempCheckpointMoney);
                moneyManagement.setEmptyingDistance(info.getEmptyNum());
                String carType = "3";
                if (StringUtils.isNotEmpty(info.getDriverCarNum())) {
                    RescueCarInfo carInfo = carInfoService.selectRescueCarInfoByNum(info.getDriverCarNum());
                    carType = carInfo.getRescueCarType();
                }
                if (carType.equals("1")) {
                    //大车
                    moneyManagement.setRoyaltyRatio(rescueTcBig);
                    moneyManagement.setRoyaltyMoney(tempSetMoney * rescueTcBig);
                } else if (carType.equals("2")) {
                    //中车
                    moneyManagement.setRoyaltyRatio(rescueTcMid);
                    moneyManagement.setRoyaltyMoney(tempSetMoney * rescueTcMid);
                } else {
                    //小车
                    moneyManagement.setRoyaltyRatio(rescueTcSmall);
                    moneyManagement.setRoyaltyMoney(tempSetMoney * rescueTcSmall);
                }
                //获取当前车 当前驾驶员 这个月跑了几次
                JSONObject driverInfoObj = baseMapper.getDriverCarNum(info.getDriverId(), info.getDriverCarNum(), rescueInfo.getRescueStart());
                //计算平均燃油费和平均油耗
                Double avgFuelConsumption = 0d;
                Double mglYh = 0d;
                if (driverInfoObj.getInteger("allNum") != 0) {
                    avgFuelConsumption = monthRescueRefuelRecord.getDouble("refuelMoney") / driverInfoObj.getInteger("allNum");
                    mglYh = monthRescueRefuelRecord.getDouble("refuelNum") / driverInfoObj.getDouble("allDistance");
                }
                moneyManagement.setFuelCost(avgFuelConsumption);
                moneyManagement.setOilConsumption(mglYh);
                Double oilSubsidy = Optional.ofNullable(info.getEmptyNum()).orElse(0d) * mglYh;
                moneyManagement.setOilSubsidy(oilSubsidy);
                grossWages = grossWages + moneyManagement.getRoyaltyMoney() + oilSubsidy - avgFuelConsumption;
                moneyManagement.setGrossWages(grossWages);
                resList.add(moneyManagement);
            }
            pageNo++;
        }
        return resList;
    }

    @Override
    public List<JSONObject> statisticsInfo(String type) {
        //所在顶级机构
        String startTime;
        String endTime = DateUtil.format(new Date(), "yyyy-MM-dd") + " 00:00:00";
        if (type.equals("day")) {
            //日
            startTime = DateUtil.format(new Date(), "yyyy-MM-dd") + " 00:00:00";
        } else if (type.equals("week")) {
            //周
            startTime = DateUtil.format(DateUtil.beginOfWeek(new Date()), "yyyy-MM-dd") + " 00:00:00";
        } else {
            //月
            startTime = DateUtil.format(DateUtil.beginOfMonth(new Date()), "yyyy-MM-dd") + " 00:00:00";
        }
        return baseMapper.statisticsInfo(startTime, endTime);
    }

    /**
     * 获取扣车单位和具体数量
     *
     * @author 小李
     * @date 10:46 2024/9/5
     **/
    @Override
    public List<BuckleVO> listBuckle() {
        // 查类型是扣车的订单数据，分组聚合求总数(查询条件是写死的)
        List<BuckleVO> buckleVOS = baseMapper.listBuckle();
        // 因为一些奇奇怪怪的原因，可能会出现没id的情况，那就算在其他里面去
        buckleVOS.forEach(item -> {
            if (ObjectUtil.isEmpty(item.getId())) {
                item.setId(0L);
                item.setBuckleName("其他");
            }
        });
        /*
            计算各自的扣车中(9)、已解扣(6)、已还车(8)、待入库的数量
            deductionCount:扣车中(9)
            unDeductionCount:已解扣(6)
            returnCount:已还车(8)
            noLibraryCount:待入库，不是前三个就是待入库
         */
        buckleVOS.forEach(item -> {
            List<RescueInfo> rescueInfos = null;
            if (item.getId().equals(0L)) {
                rescueInfos = baseMapper.selectList(new LambdaQueryWrapper<RescueInfo>().and(i -> {
                    i.eq(RescueInfo::getRescueType, "5")
                            .isNull(RescueInfo::getDeptId);
                }));
            } else {
                rescueInfos = baseMapper.selectList(new LambdaQueryWrapper<RescueInfo>().and(i -> {
                    i.eq(RescueInfo::getRescueType, "5")
                            .eq(RescueInfo::getDeptId, item.getId());
                }));
            }
            int deductionCount = 0, unDeductionCount = 0, returnCount = 0, noLibraryCount = 0;
            if (ObjectUtil.isNotEmpty(rescueInfos)) {
                for (RescueInfo rescueInfo : rescueInfos) {
                    switch (rescueInfo.getRescueStatus()) {
                        case "9":
                            deductionCount++;
                            break;
                        case "6":
                            unDeductionCount++;
                            break;
                        case "8":
                            returnCount++;
                            break;
                        default:
                            noLibraryCount++;
                            break;
                    }
                }
            }
            item.setDeductionCount(deductionCount);
            item.setUnDeductionCount(unDeductionCount);
            item.setReturnCount(returnCount);
            item.setNoLibraryCount(noLibraryCount);
        });
        return buckleVOS;
    }

    /**
     * 查看单个扣车单位信息
     * @author 小李
     * @date 11:44 2024/9/6
     * @param id 部门ID
     **/
    @Override
    public BuckleVO getBuckle(Long id){
        // 直接用上方写好的去查
        List<BuckleVO> buckleVOS = listBuckle();
        List<BuckleVO> result = buckleVOS.stream().filter(item -> item.getId().equals(id)).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(result)){
            throw exception0(500, "系统异常");
        }
        return result.get(0);
    }

    /**
     * 还车方法
     * @author 小李
     * @date 14:48 2024/9/6
     * @param returnCarVO 订单信息
     **/
    @Override
    @DSTransactional
    public void returnCar(ReturnCarVO returnCarVO){
        // 先判断是否存在和解扣
        RescueInfo flag = baseMapper.selectOne(new LambdaQueryWrapper<RescueInfo>().eq(RescueInfo::getId, returnCarVO.getId()));
        if (ObjectUtil.isEmpty(flag)){
            throw exception0(500, "订单不存在");
        }
        if (!flag.getRescueStatus().equals("6")){
            throw exception0(500, "车辆未解扣");
        }
        // 更新插入一条工单记录，因为还车也要拍照什么的
        RescueInfoDetail detail = new RescueInfoDetail();
        detail.setRescueInfoId(returnCarVO.getId());
        // type不知道是什么，暂时先不要
        // detail.setType()
        detail.setTitle("还车");
        detail.setRemark(returnCarVO.getRemark());
        detail.setImages(returnCarVO.getImages());
        Long deptId = getLoginUserDeptId();
        detail.setDeptId(deptId);
        rescueInfoDetailService.save(detail);

        // 更新工单状态为已还车(8)
        RescueInfo rescueInfo = new RescueInfo();
        rescueInfo.setId(returnCarVO.getId());
        rescueInfo.setRescueStatus("8");
        baseMapper.updateById(rescueInfo);
    }

    /**
     * 入库方法
     * @author 小李
     * @date 10:37 2024/9/7
     * @param returnCarVO 订单信息
     **/
    @Override
    public void inBase(ReturnCarVO returnCarVO){
        // 先判断是否存在和完成
        RescueInfo flag = baseMapper.selectOne(new LambdaQueryWrapper<RescueInfo>().eq(RescueInfo::getId, returnCarVO.getId()));
        if (ObjectUtil.isEmpty(flag)){
            throw exception0(500, "订单不存在");
        }
        if (!flag.getRescueStatus().equals("5")){
            throw exception0(500, "订单未完成");
        }
        // 更新插入一条工单记录，因为扣车也要拍照什么的
        RescueInfoDetail detail = new RescueInfoDetail();
        detail.setRescueInfoId(returnCarVO.getId());
        // type不知道是什么，暂时先不要
        // detail.setType()
        detail.setTitle("入库");
        detail.setRemark(returnCarVO.getRemark());
        detail.setImages(returnCarVO.getImages());
        Long deptId = getLoginUserDeptId();
        detail.setDeptId(deptId);
        rescueInfoDetailService.save(detail);

        // 更新工单状态为扣车中(9)
        RescueInfo rescueInfo = new RescueInfo();
        rescueInfo.setId(returnCarVO.getId());
        rescueInfo.setRescueStatus("9");
        baseMapper.updateById(rescueInfo);
    }

    /**
     * 获取经营分析
     *
     * @param timeType
     * @return
     */
    @TenantIgnore
    @Override
    public List<Map<String, Object>> getManageAnalyze(String timeType) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        Map<String, Object> map = DateUtils.getDateTimeList(timeType);
        DateTime startTime = (DateTime) map.get("startTime");
        DateTime endTime = (DateTime) map.get("endTime");
        List<Map<String, Object>> list = baseMapper.selectManageAnalyze(startTime, endTime,loginUser.getTenantId());
        return list;
    }


    /**
     * 救援大屏获取出车次数统计
     *
     * @param timeType
     * @return
     */
    @Override
    public Map<String, Object> getDrawOutAVehicleCount(String timeType) {
        //获取日期范围、startTime、endTime
        Map<String, Object> dateMap = DateUtils.getDateTimeList(timeType);
        List<DateTime> dateList = (List<DateTime>) dateMap.get("dateList");
        DateTime startTime = (DateTime) dateMap.get("startTime");
        DateTime endTime = (DateTime) dateMap.get("endTime");
        //根据日期范围查询救援订单
        List<RescueInfo> rescueOrderInfos = this.list(new LambdaQueryWrapper<RescueInfo>()
                .between(RescueInfo::getRescueTime, startTime, endTime));
        List<String> xList = new ArrayList<>();
        List<Long> yList = new ArrayList<>();
        // 遍历日期列表，获取每个日期对应的订单数量
        for (DateTime dateTime : dateList) {
            //echarts x轴
            String dateName = DateUtils.getDateName(timeType, dateTime);
            xList.add(dateName);

            List<RescueInfo> infos = filterRescueInfoByDate(rescueOrderInfos, dateTime, DateUtils.getEndTime(timeType, dateTime));
            //echarts y轴
            long count = infos.stream().count();
            yList.add(count);
        }

        Map<String, Object> map = new HashMap<>();
        map.put("xList", xList);
        map.put("yList", yList);
        return map;
    }

    /**
     * 救援大屏获取司机排名
     *
     * @param timeType
     * @return
     */
    @Override
    public List<Map<String, Object>> getDriverSort(String timeType) {
        Map<String, Object> map = DateUtils.getDateTimeList(timeType);
        DateTime startTime = (DateTime) map.get("startTime");
        DateTime endTime = (DateTime) map.get("endTime");
        return baseMapper.selectDriverSort(startTime, endTime);
    }

    /**
     * 救援大屏获取救援订单占比接口
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> getRescueOrderByRoad() {
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        return baseMapper.selectRescueOrderByRoad("kcRescueRoad-" + user.getTenantId());
    }

    /**
     * 救援大屏获取救援详细数据
     *
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public Map<String, Object> getRescueMessage(String startTime, String endTime) {
        Map<String, Object> resp = new HashMap<>();
        // 一.查询救援订单
        List<RescueOrderInfo> rescueOrders = rescueOrderInfoService.list(new LambdaQueryWrapper<RescueOrderInfo>()
                .between(RescueOrderInfo::getCreateTime, startTime, endTime));

        // 1.计算救援金额
        long totalRescueMoney = rescueOrders.stream().mapToLong(order -> order.getPayMoney() != null ? order.getPayMoney() : 0L).sum();
        resp.put("totalRescueMoney", totalRescueMoney);
        // 2.计算出车次数
        long totalOutCarCount = rescueOrders.size();
        resp.put("totalOutCarCount", totalOutCarCount);
        // 3.计算待支付订单数量
        long totalPayOrderCount = rescueOrders.stream().filter(info -> info.getOrderStatus().equals("1")).count();
        resp.put("totalPayOrderCount", totalPayOrderCount);

        // 二.查询加油记录表
        List<RescueRefuelRecord> rescueRefuelRecords = refuelRecordService.list(new LambdaQueryWrapper<RescueRefuelRecord>()
                .between(RescueRefuelRecord::getRecordTime, startTime, endTime));
        // 1.计算加油金额
        Double totalRefuelMoney = rescueRefuelRecords.stream().mapToDouble(RescueRefuelRecord::getRefuelMoney).sum();
        resp.put("totalRefuelMoney", totalRefuelMoney);

        // 三.查询救援信息表
        List<RescueInfo> rescueInfos = baseMapper.selectList(new LambdaQueryWrapper<RescueInfo>()
                .between(RescueInfo::getRescueTime, startTime, endTime));
        // 1.计算待取车数量
        long totalWaitCarCount = rescueInfos.stream().filter(info -> info.getRescueStatus().equals("6")).count();
        resp.put("totalWaitCarCount", totalWaitCarCount);
        // 2.计算救援中数量
        long totalRescueingCarCount = rescueInfos.stream().filter(info -> info.getRescueStatus().equals("3")).count();
        resp.put("totalRescueingCarCount", totalRescueingCarCount);
        // 3.计算已完成数量
        long totalCompletedCarCount = rescueInfos.stream().filter(info -> info.getRescueStatus().equals("5")).count();
        resp.put("totalCompletedCarCount", totalCompletedCarCount);
        // 4.计算扣车中
        long totalDeductedCarCount = rescueInfos.stream().filter(info -> info.getRescueStatus().equals("9")).count();
        resp.put("totalDeductedCarCount", totalDeductedCarCount);
        // 5.计算以还车
        long totalReturnCarCount = rescueInfos.stream().filter(info -> info.getRescueStatus().equals("8")).count();
        resp.put("totalReturnCarCount", totalReturnCarCount);

        // 四.查询司机提成表
        Double rescueTcBig = 0d;
        Double rescueTcMid = 0d;
        Double rescueTcSmall = 0d;
        RescueConfig rescueConfig = rescueConfigService.selectRescueConfigByDeptId();
        if (ObjectUtils.isNotEmpty(rescueConfig)) {
            rescueTcBig = Optional.ofNullable(rescueConfig.getRescueTcBig()).orElse(0d);
            rescueTcMid = Optional.ofNullable(rescueConfig.getRescueTcMid()).orElse(0d);
            rescueTcSmall = Optional.ofNullable(rescueConfig.getRescueTcSmall()).orElse(0d);
        }

        Double totalRoyaltyMoney = 0d;

        // 1.将救援信息转为map
        Map<Long, RescueInfo> rescueInfoMap = rescueInfos.stream().collect(Collectors.toMap(RescueInfo::getId, Function.identity()));

        // 2.循环救援订单 计算提成
        for (RescueOrderInfo info : rescueOrders) {
            RescueInfo rescueInfo = rescueInfoMap.get(info.getRescueInfoId());
            if (ObjectUtil.isNotNull(rescueInfo) && ObjectUtil.isNotEmpty(rescueInfo.getCarType())) {
                String carType = rescueInfo.getCarType();
                Double tempSetMoney = ObjectUtils.isNotEmpty(info.getSetMoney()) ? Double.valueOf(info.getSetMoney()) / 100d : 0d;
                switch (carType) {
                    case "1":
                        // 大车
                        totalRoyaltyMoney += tempSetMoney * rescueTcBig;
                        break;
                    case "2":
                        // 中车
                        totalRoyaltyMoney += tempSetMoney * rescueTcMid;
                        break;
                    case "3":
                        // 小车
                        totalRoyaltyMoney += tempSetMoney * rescueTcSmall;
                        break;
                }
            }
        }
        resp.put("totalRoyaltyMoney", totalRoyaltyMoney);
        return resp;
    }

    public List<RescueInfo> filterRescueInfoByDate(List<RescueInfo> rescueInfos, Date startTime, Date endTime) {
        return rescueInfos.stream()
                .filter(info -> info.getRescueTime() != null &&
                        !info.getRescueTime().before(startTime) &&
                        !info.getRescueTime().after(endTime))
                .collect(Collectors.toList());
    }
}
