package com.xxfc.platform.vehicle.biz;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.wxiaoqi.security.admin.feign.UserFeign;
import com.github.wxiaoqi.security.admin.feign.dto.UserDTO;
import com.github.wxiaoqi.security.admin.feign.rest.UserRestInterface;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.util.Query;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xxfc.platform.universal.utils.DateUtil;
import com.xxfc.platform.vehicle.common.RestResponse;
import com.xxfc.platform.vehicle.constant.BookType;
import com.xxfc.platform.vehicle.constant.RedisKey;
import com.xxfc.platform.vehicle.constant.ResCode.ResCode;
import com.xxfc.platform.vehicle.constant.VehicleBookRecordStatus;
import com.xxfc.platform.vehicle.entity.*;
import com.xxfc.platform.vehicle.mapper.BookRecordAccItemMapper;
import com.xxfc.platform.vehicle.mapper.VehicleBookRecordMapper;
import com.xxfc.platform.vehicle.pojo.*;
import com.xxfc.platform.vehicle.pojo.dto.VehiclePlanDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.github.wxiaoqi.security.auth.common.constatns.CommonConstants.DATA_ALL_FALSE;

@Service
@Slf4j
public class VehicleBookRecordBiz extends BaseBiz<VehicleBookRecordMapper, VehicleBookRecord> implements UserRestInterface {

    public static final String TB_NAME_PREFIX = "vehicle_book_record_his_";
    public static final String TB_NAME_REAL = "vehicle_book_record";//实际表名
    public static final String TB_ACC_ITEM_NAME_PREFIX = "book_record_acc_item_his_";
    public static final String TB_ACC_ITEM_NAME_REAL = "book_record_acc_item";//实际表名
    public static final DateTimeFormatter YEAR_DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyy");
    public static final DateTimeFormatter YEARMONTH_DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyy-MM");
    public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
    public static final Integer DEL_BATCH_SIZE = 1000;
    public static final Integer COPY_BATCH_SIZE = 100;

    @Autowired
    private RedisTemplate customRedisTemplate;
    @Autowired
    private BookRecordAccItemMapper bookRecordAccItemMapper;

    @Autowired
    BranchCompanyBiz branchCompanyBiz;

    @Autowired
    UserFeign userFeign;
    @Autowired
    VehicleUpkeepService vehicleUpkeepService;

    @Autowired
    VehicleBookHourInfoBiz vehicleBookHourInfoBiz;
    @Autowired
    VehicleDepartureService vehicleDepartureService;

    @Override
    public UserFeign getUserFeign() {
        return userFeign;
    }

    public void save(VehicleBookRecord vehicleBookRecord) {
        insertSelectiveRe(vehicleBookRecord);
    }

    public List<VehicleBookRecordVo> selectByVehicleIdAndTime(Map<String, Object> param) {
        List<VehicleBookRecordVo> list = mapper.selectByVehicleIdAndTime(param);
        removeStatus2(list);
        return list;
    }

    public List<VehicleBookRecordVo> selectZeroHourRecord(Map<String, Object> param) {
        List<VehicleBookRecordVo> list = mapper.selectZeroHourRecord(param);
        removeStatus2(list);
        return list;
    }

    public int changeRecordStatus(Map<String, Object> updateParam) {
        return mapper.changeRecordStatus(updateParam);
    }

    public QueryVehicleBookRecordVo getById(Long id, DateTime endDate) throws Exception {
        Map<String, Object> recordParams = Maps.newHashMap();
        recordParams.put("id", id);
        recordParams.put("tbName", TB_NAME_REAL);
        DateTime selectedMonthDate = endDate.withMillisOfDay(0).withDayOfMonth(1);
        String bookRecordAccItemTbName = TB_ACC_ITEM_NAME_REAL;
        if (selectedMonthDate.compareTo(DateTime.now().plusMonths(-1).withDayOfMonth(1).withMillisOfDay(0)) < 0) {
            recordParams.put("tbName", getTbName(String.valueOf(selectedMonthDate.getYear())));
            bookRecordAccItemTbName = getAccItemTbName(String.valueOf(selectedMonthDate.getYear()));
        }
        VehicleBookRecord vehicleBookRecord = mapper.getById(recordParams);
        QueryVehicleBookRecordVo queryVehicleBookRecordVo = new QueryVehicleBookRecordVo();
        BeanUtils.copyProperties(queryVehicleBookRecordVo, vehicleBookRecord);
        Map<Long, Map<Integer, Integer>> rs = getRelatedAccItemsAndAmount(Lists.newArrayList(queryVehicleBookRecordVo), bookRecordAccItemTbName);
        queryVehicleBookRecordVo.setAccItemAndAmount(rs.get(queryVehicleBookRecordVo.getId()));
        return queryVehicleBookRecordVo;
    }

    public RestResponse<PageDataVO> getBookRecord(VehicleBookRecordQueryVo vehicleBookRecordQueryVo) {
        Integer pageNo = vehicleBookRecordQueryVo.getPage() == null ? 1 : vehicleBookRecordQueryVo.getPage();
        Integer pageSize = vehicleBookRecordQueryVo.getLimit() == null ? 10 : vehicleBookRecordQueryVo.getLimit();
        vehicleBookRecordQueryVo.setPage(pageNo);
        vehicleBookRecordQueryVo.setLimit(pageSize);
        UserDTO userDTO = getAdminUserInfo();
        if (userDTO == null) {
            return RestResponse.codeAndMessage(235, "token失效");
        }
        List<Integer> companyList = Lists.newArrayList();
        if (DATA_ALL_FALSE.equals(userDTO.getDataAll())) { //不能获取全部数据
            companyList = dataCompany(userDTO.getDataZone(), userDTO.getDataCompany());
            if (vehicleBookRecordQueryVo.getCompanyId() != null) {
                if (companyList.contains(vehicleBookRecordQueryVo.getCompanyId())) { //如果权限中有这个公司就允许查询， 否则就直接返回空
                    companyList.clear();
                    companyList.add(vehicleBookRecordQueryVo.getCompanyId());
                } else {
                    return RestResponse.suc();
                }
            }
        } else {
            if (vehicleBookRecordQueryVo.getCompanyId() != null) {
                companyList.add(vehicleBookRecordQueryVo.getCompanyId());
            }
        }
        vehicleBookRecordQueryVo.setCompanyIds(companyList);
        Query query = new Query(vehicleBookRecordQueryVo);
        PageDataVO<VehicleBookRecordVo> pageDataVO = PageDataVO.pageInfo(query, () -> mapper.getBookRecordInfo(query.getSuper()));
        getupKeeps(pageDataVO.getData());
        return RestResponse.suc(pageDataVO);
    }


    public RestResponse<PageDataVO> getBookRecordInfo(VehicleBookRecordQueryVo vehicleBookRecordQueryVo) {
        Integer pageNo = vehicleBookRecordQueryVo.getPage() == null ? 1 : vehicleBookRecordQueryVo.getPage();
        Integer pageSize = vehicleBookRecordQueryVo.getLimit() == null ? 10 : vehicleBookRecordQueryVo.getLimit();
        vehicleBookRecordQueryVo.setPage(pageNo);
        vehicleBookRecordQueryVo.setLimit(pageSize);
        UserDTO userDTO = getAdminUserInfo();
        if (userDTO == null) {
            return RestResponse.codeAndMessage(235, "token失效");
        }
        vehicleBookRecordQueryVo.setUserCompany(userDTO.getCompanyId());
        List<Integer> companyList = Lists.newArrayList();
        if (DATA_ALL_FALSE.equals(userDTO.getDataAll())) { //不能获取全部数据
            companyList = dataCompany(userDTO.getDataZone(), userDTO.getDataCompany());
            if (vehicleBookRecordQueryVo.getCompanyId() != null) {
                if (companyList.contains(vehicleBookRecordQueryVo.getCompanyId())) { //如果权限中有这个公司就允许查询， 否则就直接返回空
                    companyList.clear();
                    companyList.add(vehicleBookRecordQueryVo.getCompanyId());
                } else {
                    return RestResponse.suc();
                }
            }
            if (vehicleBookRecordQueryVo.getLiftCompany() != null) {
                if (companyList.contains(vehicleBookRecordQueryVo.getLiftCompany())) { //如果权限中有这个公司就允许查询， 否则就直接返回空
                    companyList.clear();
                    companyList.add(vehicleBookRecordQueryVo.getLiftCompany());
                } else {
                    return RestResponse.suc();
                }
            }
        } else {
            if (vehicleBookRecordQueryVo.getCompanyId() != null) {
                companyList.add(vehicleBookRecordQueryVo.getCompanyId());
            }
            if (vehicleBookRecordQueryVo.getLiftCompany() != null) {
                companyList.add(vehicleBookRecordQueryVo.getLiftCompany());
            }
        }
        vehicleBookRecordQueryVo.setCompanyIds(companyList);
        if (vehicleBookRecordQueryVo.getStatus() != null && vehicleBookRecordQueryVo.getStatus() == 3) { //待出行
            vehicleBookRecordQueryVo.setStatus(2);
            Query query = new Query(vehicleBookRecordQueryVo);
            List<VehicleBookRecordVo> list = mapper.getBookRecordInfo(query.getSuper());
            removeStatus3(list);
            PageInfo<VehicleBookRecordVo> vehicleBookRecordVoPageInfo = new PageInfo<>(list);
            getupKeeps(vehicleBookRecordVoPageInfo.getList());
            PageDataVO<VehicleBookRecordVo> vehicleBookRecordVoPageDataVO = PageDataVO.pageInfo(vehicleBookRecordVoPageInfo);
            vehicleBookRecordVoPageDataVO.setPageNum(pageNo);
            vehicleBookRecordVoPageDataVO.setPageSize(pageSize);
            vehicleBookRecordVoPageDataVO.setTotalCount((long) vehicleBookRecordVoPageInfo.getList().size());
            vehicleBookRecordVoPageDataVO.setTotalPage((vehicleBookRecordVoPageInfo.getList().size() + pageSize - 1) / pageSize);
            vehicleBookRecordVoPageDataVO.setData(getData(vehicleBookRecordVoPageInfo.getList(), pageNo, pageSize));
            return RestResponse.suc(vehicleBookRecordVoPageDataVO);
        }
        if (vehicleBookRecordQueryVo.getStatus() != null && vehicleBookRecordQueryVo.getStatus() == 5) { //出行中
            vehicleBookRecordQueryVo.setStatus(2);
            Query query = new Query(vehicleBookRecordQueryVo);
            List<VehicleBookRecordVo> list = mapper.getBookRecordInfo(query.getSuper());
            removeStatus5(list);
            PageInfo<VehicleBookRecordVo> vehicleBookRecordVoPageInfo = new PageInfo<>(list);
            getupKeeps(vehicleBookRecordVoPageInfo.getList());
            PageDataVO<VehicleBookRecordVo> vehicleBookRecordVoPageDataVO = PageDataVO.pageInfo(vehicleBookRecordVoPageInfo);
            vehicleBookRecordVoPageDataVO.setPageNum(pageNo);
            vehicleBookRecordVoPageDataVO.setPageSize(pageSize);
            vehicleBookRecordVoPageDataVO.setTotalCount((long) vehicleBookRecordVoPageInfo.getList().size());
            vehicleBookRecordVoPageDataVO.setTotalPage((vehicleBookRecordVoPageInfo.getList().size() + pageSize - 1) / pageSize);
            vehicleBookRecordVoPageDataVO.setData(getData(vehicleBookRecordVoPageInfo.getList(), pageNo, pageSize));
            return RestResponse.suc(vehicleBookRecordVoPageDataVO);
        }
        if (vehicleBookRecordQueryVo.getStatus() != null && vehicleBookRecordQueryVo.getStatus() == 7) { //已完成
            vehicleBookRecordQueryVo.setStatus(2);
            Query query =  new Query(vehicleBookRecordQueryVo);
            List<VehicleBookRecordVo> list = mapper.getBookRecordInfo(query.getSuper());
            removeStatus7(list);
            PageInfo<VehicleBookRecordVo> vehicleBookRecordVoPageInfo = new PageInfo<>(list);
            getupKeeps(vehicleBookRecordVoPageInfo.getList());
            PageDataVO<VehicleBookRecordVo> vehicleBookRecordVoPageDataVO = PageDataVO.pageInfo(vehicleBookRecordVoPageInfo);
            vehicleBookRecordVoPageDataVO.setPageNum(pageNo);
            vehicleBookRecordVoPageDataVO.setPageSize(pageSize);
            vehicleBookRecordVoPageDataVO.setTotalCount((long) vehicleBookRecordVoPageInfo.getList().size());
            vehicleBookRecordVoPageDataVO.setTotalPage((vehicleBookRecordVoPageInfo.getList().size() + pageSize - 1) / pageSize);
            vehicleBookRecordVoPageDataVO.setData(getData(vehicleBookRecordVoPageInfo.getList(), pageNo, pageSize));
            return RestResponse.suc(vehicleBookRecordVoPageDataVO);
        }
        Query query =  new Query(vehicleBookRecordQueryVo);
        PageDataVO<VehicleBookRecordVo> pageDataVO = PageDataVO.pageInfo(query, () -> mapper.getBookRecordInfo(query.getSuper()));
        getupKeeps(pageDataVO.getData());
        return RestResponse.suc(pageDataVO);
    }

    //筛选未出车的记录
    public void removeStatus2(List<VehicleBookRecordVo> list) {
        if (list != null && list.size() > 0) {
            Iterator<VehicleBookRecordVo> iterator = list.iterator();
            while (iterator.hasNext()) {
                VehicleBookRecordVo vehicleBookRecordVo = iterator.next();
                //已出车记录
                if (vehicleBookRecordVo.getVehicleDepartureLogVo() != null) {
                    iterator.remove();
                }
            }
        }
    }

    //筛选未出车的记录
    public void removeStatus3(List<VehicleBookRecordVo> list) {
        if (list != null && list.size() > 0) {
            Iterator<VehicleBookRecordVo> iterator = list.iterator();
            while (iterator.hasNext()) {
                VehicleBookRecordVo vehicleBookRecordVo = iterator.next();
                if (vehicleBookRecordVo.getVehicleDepartureLogVo() != null) {
                    iterator.remove();
                }
                vehicleBookRecordVo.setState(3);
            }
        }
    }

    //筛选已出车未还车记录
    public void removeStatus5(List<VehicleBookRecordVo> list) {
        if (list != null && list.size() > 0) {
            Iterator<VehicleBookRecordVo> iterator = list.iterator();
            while (iterator.hasNext()) {
                VehicleBookRecordVo vehicleBookRecordVo = iterator.next();
                if (vehicleBookRecordVo.getVehicleDepartureLogVo() == null || (vehicleBookRecordVo.getVehicleDepartureLogVo() != null && vehicleBookRecordVo.getVehicleDepartureLogVo().getState() ==1)) {
                    iterator.remove();
                }
                vehicleBookRecordVo.setState(5);
            }
        }
    }
    //筛选已完成记录
    public void removeStatus7(List<VehicleBookRecordVo> list) {
        if (list != null && list.size() > 0) {
            Iterator<VehicleBookRecordVo> iterator = list.iterator();
            while (iterator.hasNext()) {
                VehicleBookRecordVo vehicleBookRecordVo = iterator.next();
                if (vehicleBookRecordVo.getVehicleDepartureLogVo() == null || (vehicleBookRecordVo.getVehicleDepartureLogVo() != null && vehicleBookRecordVo.getVehicleDepartureLogVo().getState() !=1)) {
                    iterator.remove();
                }
                vehicleBookRecordVo.setState(5);
            }
        }
    }
    /**
     * 获取随身物品
     */
    public List<VehicleBookRecordVo> getupKeeps(List<VehicleBookRecordVo> vehicleBookRecordVos) {
        for (VehicleBookRecordVo vehicleBookRecordVo : vehicleBookRecordVos) {
            if (vehicleBookRecordVo.getBookType() == BookType.MAINTAIN.getCode()) {//获取 保养项目
                if (StringUtils.isNotBlank(vehicleBookRecordVo.getUpkeepIds())) {
                    List<Integer> upKeeps = Arrays.asList(vehicleBookRecordVo.getUpkeepIds().split(",")).parallelStream().map(s -> Integer.valueOf(s)).collect(Collectors.toList());
                    if (upKeeps.size() > 0) {
                        List<VehicleUpkeepItem> vehicleUpkeepItems = vehicleUpkeepService.getUpkeepsByIds(upKeeps);
                        vehicleBookRecordVo.setVehicleUpkeepItems(vehicleUpkeepItems);
                    }
                }
            }
            if (vehicleBookRecordVo.getBookUser() != null) {
                UserDTO userDTO = userFeign.userinfoByUid(vehicleBookRecordVo.getBookUser()).getData();
                if(userDTO != null) {
                    BranchCompany branchCompany = branchCompanyBiz.getById(userDTO.getCompanyId());
                    if (branchCompany != null) {
                        vehicleBookRecordVo.setUserCompanyName(branchCompany.getName());
                    }
                }
            }
        }
        return vehicleBookRecordVos;
    }

    public ObjectRestResponse<List<VehicleBookRecordVo>> selectByIds(List<Long> ids) {
        Map<String, Object> map = new HashMap<>();
        map.put("ids", ids);
        return ObjectRestResponse.succ(mapper.selectByIds(map));
    }

    public RestResponse<Integer> lift(Integer operatorId, String userName, LiftVehicleVo liftVehicleVo) throws Exception {
        Map<String, Object> params = PropertyUtils.describe(liftVehicleVo);
        params.put("reviewerLift", operatorId);
        params.put("reviewerNameLift", userName);
        params.put("targetStatus", VehicleBookRecordStatus.LIFTED.getCode());
        params.put("conditionStatus", VehicleBookRecordStatus.APPROVE.getCode());
        params.put("mileageLift", liftVehicleVo.getMileageLift());
        Integer effected = mapper.liftOrRet(params);
        if (effected == 0) {
            return RestResponse.code(ResCode.VEHICLE_BOOKED_RECORD_STATUS_CHANGED.getCode());
        }
        return RestResponse.suc();
    }

    public RestResponse<Integer> retVehicle(Integer operatorId, String userName, RetVehicleVo retVehicleVo) throws Exception {
        VehicleBookRecord record = mapper.selectByPrimaryKey(retVehicleVo.getId());
        Integer mileageRet = retVehicleVo.getMileageRet();
        if (record == null || mileageRet == null) {
            //return RestResponse.code(ResCode.VEHICLE_BOOKED_RECORD_MILEAGE_CHANGED.getCode());
            throw new BaseException(ResCode.VEHICLE_BOOKED_RECORD_MILEAGE_CHANGED.getDesc(), ResCode.VEHICLE_BOOKED_RECORD_MILEAGE_CHANGED.getCode());
        }

        Integer mileageLift = record.getMileageLift();
        if (mileageLift != null && mileageRet >= mileageLift) {
            Map<String, Object> params = PropertyUtils.describe(retVehicleVo);
            params.put("targetStatus", VehicleBookRecordStatus.RETURNED.getCode());
            params.put("conditionStatus", VehicleBookRecordStatus.LIFTED.getCode());
            params.put("reviewerReturn", operatorId);
            params.put("reviewerNameReturn", userName);
            params.put("mileageRet", mileageRet);
            params.put("haveViolation", retVehicleVo.getHaveViolation());
            Integer effected = mapper.liftOrRet(params);
            if (effected == 0) {
                return RestResponse.code(ResCode.VEHICLE_BOOKED_RECORD_STATUS_CHANGED.getCode());
            }
        } else {
            throw new BaseException(ResCode.VEHICLE_BOOKED_RECORD_MILEAGE_CHANGED.getDesc(), ResCode.VEHICLE_BOOKED_RECORD_MILEAGE_CHANGED.getCode());
        }
        return RestResponse.suc();
    }

    /**
     * 按页查询
     *
     * @param vehicleBookRecordQueryVo
     * @return
     * @throws Exception
     */
    public PageDataVO<QueryVehicleBookRecordVo> page(VehicleBookRecordQueryVo vehicleBookRecordQueryVo, List<Integer> companyList) throws Exception {
        Map<String, Object> params = PropertyUtils.describe(vehicleBookRecordQueryVo);
        String bookRecordAccItemTbName = TB_ACC_ITEM_NAME_REAL;
        params.put("tbName", TB_NAME_REAL);
        if (params.get("selectedMonth") != null) {
            String selectedMonth = (String) params.get("selectedMonth");
            if (StringUtils.isBlank(selectedMonth)) {
                throw new BaseException(" no month selected ");
            }
            DateTime selectedMonthDate = DateTime.parse(selectedMonth, YEARMONTH_DATE_TIME_FORMATTER);
            if (selectedMonthDate.compareTo(DateTime.now().plusMonths(-1).withDayOfMonth(1).withMillisOfDay(0)) < 0) {
                params.put("tbName", getTbName(String.valueOf(selectedMonthDate.getYear())));
                bookRecordAccItemTbName = getAccItemTbName(String.valueOf(selectedMonthDate.getYear()));
            }
            params.put("bookedStartDate", selectedMonthDate.withDayOfMonth(1).toString());
            params.put("bookedEndDate", selectedMonthDate.plusMonths(1).withDayOfMonth(1).toDate());
        }
        Integer pageSize = (Integer) params.get("limit");
        params.remove("pageSize");
        Integer pageNo = (Integer) params.get("page");
        params.remove("pageNo");
        params.put("companyList", companyList);
        PageHelper.startPage(pageNo, pageSize);
        List<QueryVehicleBookRecordVo> bookRecordAndVehicleInfo = mapper.getByPage(params);
        Map<Long, Map<Integer, Integer>> rs = getRelatedAccItemsAndAmount(bookRecordAndVehicleInfo,
                bookRecordAccItemTbName);
        //获取相关随行物品信息
        for (QueryVehicleBookRecordVo queryVehicleBookRecordVo : bookRecordAndVehicleInfo) {
            queryVehicleBookRecordVo.setAccItemAndAmount(rs.get(queryVehicleBookRecordVo.getId()));
        }
        PageInfo<QueryVehicleBookRecordVo> vehiclePageInfo = new PageInfo<>(bookRecordAndVehicleInfo);
        return PageDataVO.pageInfo(vehiclePageInfo);
    }

    public List<VehicleBookRecordVo> selectByVehicleId(String vehicleId) {
        return mapper.selectByVehicleId(vehicleId);
    }


    /**
     * 获取相关申请记录对应随行物品的数量，并放入map
     *
     * @param bookRecordAndVehicleInfos
     * @return
     */
    public Map<Long, Map<Integer, Integer>> getRelatedAccItemsAndAmount(List<QueryVehicleBookRecordVo> bookRecordAndVehicleInfos,
                                                                        String tbName) {
        List<Long> bookRecordIds = Lists.newArrayList();
        if (CollectionUtils.isEmpty(bookRecordAndVehicleInfos)) {
            return null;
        }
        for (QueryVehicleBookRecordVo queryVehicleBookRecordVo : bookRecordAndVehicleInfos) {
            bookRecordIds.add(queryVehicleBookRecordVo.getId());
        }


        List<BookRecordAccItem> bookRecordAccItems = bookRecordAccItemMapper.getByRecords(ImmutableMap.of("bookRecordIds", bookRecordIds,
                "tbName", tbName));
        Map<Long, Map<Integer, Integer>> rs = Maps.newHashMap();
        for (BookRecordAccItem bookRecordAccItem : bookRecordAccItems) {
            if (!rs.containsKey(bookRecordAccItem.getBookRecordId())) {
                rs.put(bookRecordAccItem.getBookRecordId(), Maps.newHashMap());
            }
            rs.get(bookRecordAccItem.getBookRecordId()).
                    put(bookRecordAccItem.getAccItemId(), bookRecordAccItem.getAmount());
        }
        return rs;
    }

    /**
     * 检验数据库预定记录日期是否和时间，日期表中的二进制数据一致
     *
     * @return
     */
    public ObjectRestResponse checkDateInvalide() {
        List<VehicleBookRecord> list = mapper.selectAll();
        List<VehicleBookRecord> unRightList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            for (VehicleBookRecord vehicleBookRecord : list) {
                log.info("vehicleBookRecord = {}", vehicleBookRecord);
                Map<String, Integer> map = vehicleBookHourInfoBiz.getPredictableHours(DateUtil.dateToStr(vehicleBookRecord.getBookStartDate(), "yyyy-MM-dd HH:mm:ss"), DateUtil.dateToStr(vehicleBookRecord.getBookStartDate(), "yyyy-MM-dd HH:mm:ss"), Boolean.TRUE);
                log.info("转换为时间二进制：map = {}", map);
                //检验数据有效性
                if (vehicleBookRecord.getStatus() == 2) {
                    VehicleDepartureLogVo vehicleDepartureLog = vehicleDepartureService.getByRecordId(vehicleBookRecord.getId());
                    if (vehicleDepartureLog == null || vehicleDepartureLog.getState() != 1) { //未出车或未还车
                        for (Map.Entry<String, Integer> entry : map.entrySet()) {
                            VehicleBookHourInfoDto vehicleBookHourInfoDto = new VehicleBookHourInfoDto();
                            vehicleBookHourInfoDto.setVehicleId(vehicleBookRecord.getVehicleId());
                            vehicleBookHourInfoDto.setYearMonthDay(entry.getKey());
                            List<VehicleBookHourInfo> vehicleBookHourInfos = vehicleBookHourInfoBiz.selectByVehicleAndDate(vehicleBookHourInfoDto);
                            log.info("预定时间信息：vehicleBookHourInfos = {}", vehicleBookHourInfos);
                            if (vehicleBookHourInfos != null && vehicleBookHourInfos.size() > 0) {
                                //检验数据是否存在
                                if ((vehicleBookHourInfos.get(0).getBookedHour() & entry.getValue()) == entry.getValue()) {
                                    log.info("时间正确，已经存在");
                                } else {
                                    log.info("时间不正确");
                                    vehicleBookHourInfos.get(0).setBookedHour((vehicleBookHourInfos.get(0).getBookedHour() | entry.getValue()));
                                    log.info("更新预定时间数据：vehicleBookHourInfos = {}", vehicleBookHourInfos);
                                    vehicleBookHourInfoBiz.updateSelectiveByIdRe(vehicleBookHourInfos.get(0));
                                    unRightList.add(vehicleBookRecord);
                                }
                            }
                        }
                    }
                }
            }

        }
        return ObjectRestResponse.succ(unRightList);
    }


    /**
     * 迁移数据到历史表
     * 每年一张表
     */
    @Scheduled(cron = "0 0 1 1 * ?")//每月1号1点触发
    public void transfer2HistoryTb() {
        try {
            //获取表格名称
            DateTime now = DateTime.now();//当前获取的时间为标准
            log.info("开始预定记录迁移至历史表的定时任务。");
            Boolean needRun = copyDataLastMoth(now);
            if (needRun) {
                //每月初将上上月数据从当前信息表中删除
                delDataTheMonthBeforeLast(now);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }

    }

    public ObjectRestResponse<List<VehicleBookRecordVo>> selectAllBookRecord(Date startTime, Date endTime, Integer status) {
        Map<String, Object> map = new HashMap<>();
        map.put("startTime", startTime);
        map.put("endTime", endTime);
        map.put("status", status);
        return ObjectRestResponse.succ(mapper.selectAllBookRecord(map));
    }

    /**
     * 获取上月数据，并复制到历史表
     */
    @Transactional
    public Boolean copyDataLastMoth(DateTime now) throws Exception {
        String lastMonthStr = now.plusMonths(-1).toString(YEARMONTH_DATE_TIME_FORMATTER);
        String redisKey = RedisKey.TRANSFER_BOOK_RECORD_LOCK_PREFIX + lastMonthStr;
        String tbName = getTbName(now.plusMonths(-1).toString("yyyy"));
        String accItemTbName = getAccItemTbName(now.plusMonths(-1).toString("yyyy"));
        Boolean hasSuc = customRedisTemplate.opsForValue().setIfAbsent(redisKey, String.valueOf(DateTime.now().getMillis()));
        if (hasSuc) {//设置1天后过期
            customRedisTemplate.expire(redisKey, 1, TimeUnit.DAYS);
        } else {
            log.info("[预定记录迁移]乐观锁获取失败，该线程不执行任务。");
            return Boolean.FALSE;
        }
        createTbIfNotExists(tbName);
        createAccItemTbIfNotExists(accItemTbName);
        //逐页查出数据
        Integer curPageNo = 1;
        List<VehicleBookRecord> vehicleBookRecords = null;
        do {
            Map<String, Object> params = Maps.newHashMap();
            params.put("startDate", now.plusMonths(-1).withMillisOfDay(0).toDate());
            params.put("endDate", now.plusDays(-1).withMillisOfDay(0).toDate());
            params.put("pageStart", (curPageNo - 1) * COPY_BATCH_SIZE);
            params.put("pageSize", COPY_BATCH_SIZE);
            vehicleBookRecords = mapper.getByPage4Month(params);
            //复制相关随行物品关系
            copyAccItemRel2His(vehicleBookRecords, accItemTbName);
            if (CollectionUtils.isNotEmpty(vehicleBookRecords)) {
                //插入数据到历史表
                for (VehicleBookRecord vehicleBookRecord : vehicleBookRecords) {
                    VehicleBookRecordAndTbNameVo vehicleBookRecordAndTbNameVo = new VehicleBookRecordAndTbNameVo();
                    BeanUtils.copyProperties(vehicleBookRecordAndTbNameVo, vehicleBookRecord);
                    vehicleBookRecordAndTbNameVo.setTbName(tbName);
                    mapper.insertHis(vehicleBookRecordAndTbNameVo);
                }
            }
            curPageNo++;
            log.info("【复制上月预定记录至历史表中】，当前复制页【" + curPageNo + "】，页大小【" + COPY_BATCH_SIZE + "】");
        } while (CollectionUtils.isNotEmpty(vehicleBookRecords));
        log.info("复制上月预定记录至历史表中完成，总页数【" + (curPageNo - 1) + "】");
        return Boolean.TRUE;
    }


    /**
     * 删除上上月数据
     */
    @Transactional
    public void delDataTheMonthBeforeLast(DateTime now) {
        Integer effected = 0;
        Integer total = 0;
        Map<String, Object> params = Maps.newHashMap();
        params.put("startDate", now.plusMonths(-2).withMillisOfDay(0).toDate());
        params.put("endDate", now.plusMonths(-1).plusDays(-1).withMillisOfDay(0).toDate());
        params.put("batchSize", DEL_BATCH_SIZE);
        do {
            //删除相关随行物品数据
            List<Long> bookRecordIds = mapper.getIdInYearMothLimit(params);
            deleteAccItemRelByRecord(bookRecordIds);
            effected = mapper.del4YearMoth(params);
            total += effected;
            log.info("开始删除预定记录数据，删除总数【" + total + "】");
        } while (effected != 0);
        log.info("删除预定记录数据完成");
    }

    /**
     * 删除随影订车记录的随行物品记录
     *
     * @param bookRecordIds
     */
    private void deleteAccItemRelByRecord(List<Long> bookRecordIds) {
        if (CollectionUtils.isEmpty(bookRecordIds)) {
            return;
        }
        Example example = new Example(BookRecordAccItem.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("bookRecordId", bookRecordIds);
        bookRecordAccItemMapper.deleteByExample(example);
    }

    /**
     * 复制相应预定记录的随行物品信息
     * （注意了参数列表中的记录的历史年份必须属于当前月）
     *
     * @param vehicleBookRecords
     */
    @Transactional
    public void copyAccItemRel2His(List<VehicleBookRecord> vehicleBookRecords, String accItemTbName) {
        if (CollectionUtils.isEmpty(vehicleBookRecords)) {
            return;
        }
        List<Long> recordIds = Lists.newArrayList();
        for (VehicleBookRecord vehicleBookRecord : vehicleBookRecords) {
            recordIds.add(vehicleBookRecord.getId());
        }
        List<BookRecordAccItem> bookRecordAccItems = bookRecordAccItemMapper.getByRecords(
                ImmutableMap.of("bookRecordIds", recordIds, "tbName", TB_ACC_ITEM_NAME_REAL));
        if (CollectionUtils.isEmpty(bookRecordAccItems)) {
            return;
        }
        List<Map<String, Object>> bookRecordAccItemsTemp = Lists.newArrayList();
        for (Integer index = 0; index < bookRecordAccItems.size(); index++) {
            bookRecordAccItemsTemp.add(ImmutableMap.of(
                    "id", bookRecordAccItems.get(index).getId(),
                    "bookRecordId", bookRecordAccItems.get(index).getBookRecordId(),
                    "accItemId", bookRecordAccItems.get(index).getAccItemId(),
                    "amount", bookRecordAccItems.get(index).getAmount()
            ));
            if (index == COPY_BATCH_SIZE || index == bookRecordAccItems.size() - 1) {
                bookRecordAccItemMapper.batchAdd2Tb(ImmutableMap.of(
                        "list", bookRecordAccItemsTemp,
                        "tbName", accItemTbName
                ));
                bookRecordAccItemsTemp = Lists.newArrayList();
            }
        }

    }


    public PageDataVO<VehicleRecordInfoVo> getListByParam(VehiclePlanDto vehiclePlanDto) {
        Query query = new Query(vehiclePlanDto);
        PageDataVO<VehicleRecordInfoVo> pageDataVO = PageDataVO.pageInfo(query, () -> mapper.getByParam(query.getSuper()));
        return pageDataVO;
    }

    private String getTbNameNow() {
        return TB_NAME_PREFIX + DateTime.now().toString(YEAR_DATE_TIME_FORMATTER);
    }

    /**
     * 获取历史表名称
     *
     * @param year
     * @return
     */
    private String getTbName(String year) {
        return TB_NAME_PREFIX + year;
    }

    private String getAccItemTbNameNow() {
        return TB_ACC_ITEM_NAME_PREFIX + DateTime.now().toString(YEAR_DATE_TIME_FORMATTER);
    }

    /**
     * 获取历史表名称
     *
     * @param year
     * @return
     */
    private String getAccItemTbName(String year) {
        return TB_ACC_ITEM_NAME_PREFIX + year;
    }

    /**
     * 创建当年相关表格
     */
    private void createTbIfNotExists(String tbName) {
        mapper.createTbIfNotExists(tbName);
    }

    private void createAccItemTbIfNotExists(String tbName) {
        bookRecordAccItemMapper.createTbIfNotExists(tbName);
    }

    public List<Integer> dataCompany(String dataZone, String dataCompany) {
        List<BranchCompany> zoneCompanys = branchCompanyBiz.dataCompany(dataZone);
        //((VehicleBiz)AopContext.currentProxy()).dataCompany(dataZone);
        List<Integer> zoneCompanyIds = zoneCompanys.parallelStream().map(BranchCompany::getId).collect(Collectors.toList());
        if (StringUtils.isNotBlank(dataCompany)) {
            List<Integer> dataCompanyIds = Arrays.asList(dataCompany.split(",")).parallelStream().map(s -> Integer.valueOf(s)).collect(Collectors.toList());
            zoneCompanyIds.addAll(dataCompanyIds);
        }
        //去重
        return zoneCompanyIds.parallelStream().distinct().collect(Collectors.toList());
    }

    public List<VehicleBookRecordVo> getData(List<VehicleBookRecordVo> data, Integer currentPage, Integer pageSize) {
        int fromIndex = (currentPage - 1) * pageSize;
        if (fromIndex >= data.size()) {
            return Collections.emptyList();//空数组
        }
        if (fromIndex < 0) {
            return Collections.emptyList();//空数组
        }
        int toIndex = currentPage * pageSize;
        if (toIndex >= data.size()) {
            toIndex = data.size();
        }
        return data.subList(fromIndex, toIndex);
    }
}
