package com.ningdatech.carapi.road.manage;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.carapi.radar.helper.RadarDataHelper;
import com.ningdatech.carapi.road.model.entity.ComprehensiveSituation;
import com.ningdatech.carapi.road.model.entity.TrafficFlow;
import com.ningdatech.carapi.road.model.vo.*;
import com.ningdatech.carapi.road.service.IComprehensiveSituationService;
import com.ningdatech.carapi.road.service.impl.ITrafficFlowServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.carapi.common.contants.DefValConstants;
import com.ningdatech.carapi.homepage.entity.model.NdDataAccessGps;
import com.ningdatech.carapi.homepage.service.IDataAccessGpsService;
import com.ningdatech.carapi.road.constant.*;
import com.ningdatech.carapi.road.model.entity.RoadBehaviorAnalysis;
import com.ningdatech.carapi.road.model.req.RoadMonitorHandleReq;
import com.ningdatech.carapi.road.model.req.RoadMonitorReq;
import com.ningdatech.carapi.road.model.req.VideoDownloadReq;
import com.ningdatech.carapi.road.service.IRoadBehaviorAnalysisService;
import com.ningdatech.carapi.scheduler.contants.TaskConstant;

import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;

/**
 * @author CMM
 * @since 2024/10/23 10:11
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RoadMonitorManage {

    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private Integer redisPort;

    @Value("${spring.redis.password}")
    private String redisPassword;

    private final IRoadBehaviorAnalysisService roadBehaviorAnalysisService;
    private final IDataAccessGpsService dataAccessGpsService;
    private final RadarDataHelper radarDataHelper;
    private final IComprehensiveSituationService comprehensiveSituationService;
    private final ITrafficFlowServiceImpl trafficFlowService;

    public ComprehensiveSituationVO getComSitData(RoadMonitorReq req) {
        Jedis jedis = new Jedis(redisHost,redisPort);
        jedis.auth(redisPassword);
        // 隧道类型 1 黄山隧道、2 何里隧道、3 两条隧道的汇总(求平均)
        Integer tunnel = req.getTunnel();
        // 根据传入的隧道类型 实时从缓存中获取算法分析的结果
        // 分区域分别计算4个指标的分值 比例按照1:1:1:1 加权计算道路安全指数
        // 黄山隧道 包含 1 黄山隧道东阳去向、2 黄山隧道东阳来向、3 黄山隧道义乌去向、4 黄山隧道义乌来向
        if (tunnel == 1){
            List<String> regionList = Lists.newArrayList("1", "2", "3", "4");
            return getCollectDataVo(regionList,jedis,tunnel);
        }
        // 何里隧道 包含 5 何里隧道兰溪方向、6 何里隧道义乌方向
        else if (tunnel == 2) {
            List<String> regionList = Lists.newArrayList("5", "6");
            return getCollectDataVo(regionList,jedis,tunnel);
        } else if (tunnel == 3) {
            List<String> regionList = Lists.newArrayList("1", "2", "3", "4", "5", "6");
            return getCollectDataVo(regionList, jedis, tunnel);
        }
        return new ComprehensiveSituationVO();
    }

    private ComprehensiveSituationVO getCollectDataVo(List<String> regionList, Jedis jedis, Integer tunnel) {
        ComprehensiveSituationVO vo = new ComprehensiveSituationVO();
        setDefaultScores(vo);

        // 使用Map来存储不同region对应的ComprehensiveSituationVO对象
        Map<String, ComprehensiveSituationVO> regionVoMap = new HashMap<>();
        // 初始化所有可能的ComprehensiveSituationVO对象并设置默认值
        ComprehensiveSituationVO hsDyGoVo;
        regionVoMap.put("1", hsDyGoVo = new ComprehensiveSituationVO());
        setDefaultScores(hsDyGoVo);
        ComprehensiveSituationVO hsDyComeVo;
        regionVoMap.put("2", hsDyComeVo = new ComprehensiveSituationVO());
        setDefaultScores(hsDyComeVo);
        ComprehensiveSituationVO hsYwGoVo;
        regionVoMap.put("3", hsYwGoVo = new ComprehensiveSituationVO());
        setDefaultScores(hsYwGoVo);
        ComprehensiveSituationVO hsYwComeVo;
        regionVoMap.put("4", hsYwComeVo = new ComprehensiveSituationVO());
        setDefaultScores(hsYwComeVo);
        ComprehensiveSituationVO hlLxVo;
        regionVoMap.put("5", hlLxVo = new ComprehensiveSituationVO());
        setDefaultScores(hlLxVo);
        ComprehensiveSituationVO hlYwVo;
        regionVoMap.put("6", hlYwVo = new ComprehensiveSituationVO());
        setDefaultScores(hlYwVo);

        // 遍历regionList获取数据
        for (String region : regionList) {
            ComprehensiveSituationVO currentVo = regionVoMap.get(region);
            if (currentVo != null) {
                switch (region) {
                    case "1":
                        getDataVo(TaskConstant.RedisKey.HS_DY_GO_REDIS_ALL_DATA_KEY, currentVo, jedis);
                        break;
                    case "2":
                        getDataVo(TaskConstant.RedisKey.HS_DY_COME_REDIS_ALL_DATA_KEY, currentVo, jedis);
                        break;
                    case "3":
                        getDataVo(TaskConstant.RedisKey.HS_YW_GO_REDIS_ALL_DATA_KEY, currentVo, jedis);
                        break;
                    case "4":
                        getDataVo(TaskConstant.RedisKey.HS_YW_COME_REDIS_ALL_DATA_KEY, currentVo, jedis);
                        break;
                    case "5":
                        getDataVo(TaskConstant.RedisKey.HL_LX_REDIS_ALL_DATA_KEY, currentVo, jedis);
                        break;
                    case "6":
                        getDataVo(TaskConstant.RedisKey.HL_YW_REDIS_ALL_DATA_KEY, currentVo, jedis);
                        break;
                }
            }
        }
        // 汇总数据
        if (tunnel == 1) {
            List<ComprehensiveSituationVO> vos = Lists.newArrayList(hsDyGoVo, hsDyComeVo, hsYwGoVo, hsYwComeVo);
            vo = averageScores(vos);
        } else if (tunnel == 2) {
            List<ComprehensiveSituationVO> vos = Lists.newArrayList(hlLxVo, hlYwVo);
            vo = averageScores(vos);
        } else if (tunnel == 3) {
            List<ComprehensiveSituationVO> vos = Lists.newArrayList(hsDyGoVo, hsDyComeVo, hsYwGoVo, hsYwComeVo, hlLxVo, hlYwVo);
            vo = averageScores(vos);
        }
        return vo;
    }

    private ComprehensiveSituationVO averageScores(List<ComprehensiveSituationVO> vos) {
        ComprehensiveSituationVO resultVo = new ComprehensiveSituationVO();
        setDefaultScores(resultVo);
        if (CollUtil.isNotEmpty(vos)) {
            int roadScore = 0, carScore = 0, driverScore = 0, environmentScore = 0, roadSafetyIndex = 0;
            for (ComprehensiveSituationVO vo : vos) {
                roadScore += vo.getRoadScore();
                carScore += vo.getCarScore();
                driverScore += vo.getDriverScore();
                environmentScore += vo.getEnvironmentScore();
                roadSafetyIndex += vo.getRoadSafetyIndex();
            }
            resultVo.setRoadScore(roadScore / vos.size());
            resultVo.setCarScore(carScore / vos.size());
            resultVo.setDriverScore(driverScore / vos.size());
            resultVo.setEnvironmentScore(environmentScore / vos.size());
            resultVo.setRoadSafetyIndex(roadSafetyIndex / vos.size());
            return resultVo;
        }
        return resultVo;
    }

    private void setDefaultScores(ComprehensiveSituationVO vo) {
        vo.setRoadScore(85);
        vo.setCarScore(85);
        vo.setDriverScore(85);
        vo.setEnvironmentScore(85);
        vo.setRoadSafetyIndex(85);
    }

    private void getDataVo(String dataKey, ComprehensiveSituationVO vo, Jedis jedis) {
        String allData = jedis.get(dataKey);

        // 解析获取数据
        JSONObject jsonObject = JSON.parseObject(allData);
        if (Objects.nonNull(jsonObject)) {

            JSONArray driver = jsonObject.getJSONArray("Driver");
            JSONArray speed = jsonObject.getJSONArray("Speed");
            JSONArray pedestrian = jsonObject.getJSONArray("Pedestrian");
            JSONArray road = jsonObject.getJSONArray("Road");
            JSONArray congestion = jsonObject.getJSONArray("Congestion");
            JSONArray weather = jsonObject.getJSONArray("Weather");
            JSONArray vehicle = jsonObject.getJSONArray("Vehicle");
            JSONArray bicycle = jsonObject.getJSONArray("Bicycle");
            JSONArray offense = jsonObject.getJSONArray("Offense");

            String time = jsonObject.getString("Time");
            String region = jsonObject.getString("Region");

            // 计算道路评分:
            // Pedestrian(Trespass -50、Traverse -50)、
            // Road(Damaged -10、Debris -10、Slippery -5)、
            // Congestion(Heavy -20、Medium -10、Light -5)、
            // Bicycle(Bicycle_Collisions -50、Motorway_Intrusion -50)
            int roadScore = vo.getRoadScore();
            if (CollUtil.isNotEmpty(pedestrian)){
                for (int i = 0; i < driver.size(); i++) {
                    String driverString = driver.getString(i);
                    if (driverString.contains("habits")) {
                        driverString = "Poor_habits";
                    }
                    DriverStatusTypeEnum driverStatusTypeEnum = DriverStatusTypeEnum.valueOf(driverString);
                    switch (driverStatusTypeEnum){
                        case Fatigue:
                        case Poor_habits:
                            roadScore -= 50;
                            break;
                    }
                }
            }
            if (CollUtil.isNotEmpty(road)){
                for (int i = 0; i < road.size(); i++) {
                    String roadString = road.getString(i);
                    RoadStatusTypeEnum roadStatusTypeEnum = RoadStatusTypeEnum.valueOf(roadString);
                    switch (roadStatusTypeEnum){
                        case Damaged:
                            roadScore -= 10;
                            break;
                        case Debris:
                            roadScore -= 10;
                            break;
                        case Slippery:
                            roadScore -= 5;
                            break;
                    }
                }
            }
            if (CollUtil.isNotEmpty(congestion)){
                for (int i = 0; i < congestion.size(); i++) {
                    String congestionString = congestion.getString(i);
                    CongestionStatusTypeEnum congestionStatusTypeEnum = CongestionStatusTypeEnum.valueOf(congestionString);
                    switch (congestionStatusTypeEnum){
                        case Heavy:
                            roadScore -= 20;
                            break;
                        case Medium:
                            roadScore -= 10;
                            break;
                        case Light:
                            roadScore -= 5;
                            break;
                    }
                }
            }
            if (CollUtil.isNotEmpty(bicycle)){
                for (int i = 0; i < bicycle.size(); i++) {
                    String bicycleString = bicycle.getString(i);
                    if (bicycleString.contains("Collision")){
                        bicycleString = "Bicycle_Collisions";
                    } else if (bicycleString.contains("Motorway")) {
                        bicycleString = "Motorway_Intrusion";
                    }
                    BicycleStatusTypeEnum bicycleStatusTypeEnum = BicycleStatusTypeEnum.valueOf(bicycleString);
                    switch (bicycleStatusTypeEnum){
                        case Bicycle_Collisions:
                        case Motorway_Intrusion:
                            roadScore -= 50;
                            break;
                    }
                }
            }
            vo.setRoadScore(roadScore);

            // 计算车辆评分
            // Speed(Over -5、Low -5、Stop -20、Reverse -50)
            // Vehicle(Vehicle_Collisions -50、Overturn -50、Smoke_or_Fire -50、Dropping -10)
            // Offense(Running_a_red_light -10、Crossing_the_line -10)
            int carScore = vo.getCarScore();
            if (CollUtil.isNotEmpty(speed)){
                for (int i = 0; i < speed.size(); i++) {
                    String speedString = speed.getString(i);
                    SpeedStatusTypeEnum speedStatusTypeEnum = SpeedStatusTypeEnum.valueOf(speedString);
                    switch (speedStatusTypeEnum){
                        case Over:
                        case Low:
                            carScore -= 5;
                            break;
                        case Stop:
                            carScore -= 20;
                            break;
                        case Reverse:
                            carScore -= 50;
                            break;
                    }
                }
            }
            if (CollUtil.isNotEmpty(vehicle)){
                for (int i = 0; i < vehicle.size(); i++) {
                    String vehicleString = vehicle.getString(i);
                    if (vehicleString.contains("Collision")){
                        vehicleString = "Vehicle_Collisions";
                    } else if (vehicleString.contains("Smoke")) {
                        vehicleString = "Smoke_or_Fire";
                    }
                    VehicleStatusTypeEnum vehicleStatusTypeEnum = VehicleStatusTypeEnum.valueOf(vehicleString);
                    switch (vehicleStatusTypeEnum){
                        case Vehicle_Collisions:
                        case Overturn:
                        case Smoke_or_Fire:
                            carScore -= 50;
                            break;
                        case Dropping:
                            carScore -= 10;
                            break;
                    }
                }
            }
            if (CollUtil.isNotEmpty(offense)){
                for (int i = 0; i < offense.size(); i++) {
                    String offenseString = offense.getString(i);
                    if (offenseString.contains("red")){
                        offenseString = "Running_a_red_light";
                    } else if (offenseString.contains("line")) {
                        offenseString = "Crossing_the_line";
                    }
                    OffenseStatusTypeEnum offenseStatusTypeEnum = OffenseStatusTypeEnum.valueOf(offenseString);
                    switch (offenseStatusTypeEnum){
                        case Running_a_red_light:
                        case Crossing_the_line:
                            carScore -= 10;
                            break;
                    }
                }
            }
            vo.setCarScore(carScore);

            // 计算驾驶员评分
            // Driver(Fatigue -5、Poor_habits -5)
            int driverScore = vo.getDriverScore();
            if (CollUtil.isNotEmpty(driver)){
                for (int i = 0; i < driver.size(); i++) {
                    String driverString = driver.getString(i);
                    if (driverString.contains("habits")) {
                        driverString = "Poor_habits";
                    }
                    DriverStatusTypeEnum driverStatusTypeEnum = DriverStatusTypeEnum.valueOf(driverString);
                    switch (driverStatusTypeEnum){
                        case Fatigue:
                        case Poor_habits:
                            driverScore -= 5;
                            break;
                    }
                }
            }
            vo.setDriverScore(driverScore);

            // 计算环境评分
            // Weather(Fog -10、Rain -10、Snow -10、Wind -10、Sandstorm -10)
            int environmentScore = vo.getEnvironmentScore();
            if (CollUtil.isNotEmpty(weather)){
                for (int i = 0; i < weather.size(); i++) {
                    String weatherString = weather.getString(i);
                    WeatherStatusTypeEnum weatherStatusTypeEnum = WeatherStatusTypeEnum.valueOf(weatherString);
                    switch (weatherStatusTypeEnum){
                        case Fog:
                        case Rain:
                        case Snow:
                        case Wind:
                        case Sandstorm:
                            environmentScore -= 10;
                            break;
                    }
                }
            }
            vo.setEnvironmentScore(environmentScore);

            // 计算道路安全指数 按照1:1:1:1的比例计算
            int roadSafetyIndex = (roadScore + carScore + driverScore + environmentScore) / 4;
            vo.setRoadSafetyIndex(roadSafetyIndex);
        }
    }

    public PageVo<RoadDangerBehaviorVO> getRoadDangerBehaviorData(RoadMonitorReq req) {
        List<String> regionList = req.getRegionList();
        // 从列表中查询数据
        Page<RoadBehaviorAnalysis> pageResult = roadBehaviorAnalysisService.page(new Page<>(req.getPageNumber(), req.getPageSize()),
                Wrappers.lambdaQuery(RoadBehaviorAnalysis.class)
                        .in(RoadBehaviorAnalysis::getRegion, regionList)
                        .like(StringUtils.isNoneBlank(req.getBehavior()), RoadBehaviorAnalysis::getBehavior, req.getBehavior())
                        .eq(Objects.nonNull(req.getType()), RoadBehaviorAnalysis::getType, req.getType())
                        .ge(Objects.nonNull(req.getStartTime()), RoadBehaviorAnalysis::getBehaviorTime, req.getStartTime())
                        .le(Objects.nonNull(req.getEndTime()), RoadBehaviorAnalysis::getBehaviorTime, req.getEndTime())
                        .eq(Objects.nonNull(req.getIsWarn()), RoadBehaviorAnalysis::getIsWarn, req.getIsWarn())
                        .orderByDesc(RoadBehaviorAnalysis::getBehaviorTime));
        if (CollUtil.isEmpty(pageResult.getRecords())){
            return PageVo.empty();
        }
        List<RoadDangerBehaviorVO> collect = pageResult.getRecords().stream().map(roadBehaviorAnalysis -> {
            RoadDangerBehaviorVO vo = new RoadDangerBehaviorVO();
            vo.setId(roadBehaviorAnalysis.getId());
            vo.setRecord(roadBehaviorAnalysis.getBehavior());
            vo.setRecordCode(roadBehaviorAnalysis.getBehaviorCode());
            vo.setRecordTime(roadBehaviorAnalysis.getBehaviorTime());
            vo.setRecordType(RoadBehaviorTypeEnum.getDescByCode(roadBehaviorAnalysis.getType()));
            vo.setRegion(roadBehaviorAnalysis.getRegion());
            vo.setPicturePath(roadBehaviorAnalysis.getPicturePath());
            vo.setOverspeedPositionInfo(roadBehaviorAnalysis.getOverspeedPositionInfo());
            vo.setIsWarn(roadBehaviorAnalysis.getIsWarn());
            vo.setIsHandled(roadBehaviorAnalysis.getIsHandled());
            return vo;
        }).collect(Collectors.toList());
        return  PageVo.of(collect,pageResult.getTotal());
    }

    public void videoDownload(VideoDownloadReq req, HttpServletResponse response) {

        String videoType = req.getVideoType();
        String videoOrder = req.getVideoOrder();

        File directory = new File("");
        // 拼接对应的filePath
        String filePath = null;
        // 设置响应内容类型
        // 对于MP4文件
        response.setContentType("video/mp4");
        // 隧道回放视频
        if (StringUtils.equals("1", videoType)){
            filePath = directory.getAbsolutePath() + File.separator + DefValConstants.SUI_DAO_PLAY_BACK + File.separator + videoOrder + ".mp4";
        }
        // 驾驶员监控实时视频
        else if (StringUtils.equals("2", videoType)) {
            filePath = directory.getAbsolutePath() + File.separator + DefValConstants.DRIVER_REAL_TIME_PLAY_BACK + File.separator + videoOrder + ".mp4";
        }
        // 驾驶员监控远程回放
        else if (StringUtils.equals("3", videoType)) {
            filePath = directory.getAbsolutePath() + File.separator + DefValConstants.DRIVER_REMOTE_PLAY_BACK + File.separator + videoOrder + ".mp4";
        }

        assert filePath != null;
        File file = new File(filePath);

        // 设置文件名（将显示在下载对话框中）
        response.setHeader("Content-Disposition", "inline;");
        // 设置文件大小，这样浏览器可以显示下载进度
        response.setContentLengthLong(file.length());

        // 设置缓存控制头
        response.setHeader("Cache-Control", "public, max-age=31536000");

        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            ServletOutputStream servletOutputStream = response.getOutputStream();

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                servletOutputStream.write(buffer, 0, bytesRead);
            }
            fileInputStream.close();
            servletOutputStream.close();
        } catch (IOException e) {
            throw new BizException("文件下载失败! {}",e);
        }
    }

    public List<RoadDangerBehaviorVO> getViolationWarnRecordData(RoadMonitorReq req) {
        // 从列表中查询数据
        List<RoadBehaviorAnalysis> list = roadBehaviorAnalysisService.list(Wrappers.lambdaQuery(RoadBehaviorAnalysis.class)
                // 不传类型返回所有需预警数据
                .eq(Objects.nonNull(req.getType()), RoadBehaviorAnalysis::getType, req.getType())
                // 所选隧道包含区域
                .in(RoadBehaviorAnalysis::getRegion, req.getRegionList())
                // 需要预警的数据
                .eq(RoadBehaviorAnalysis::getIsWarn, Boolean.TRUE)
                // 查看某个具体区域的数据
                .eq(Objects.nonNull(req.getRegion()),RoadBehaviorAnalysis::getRegion, req.getRegion())
                .orderByDesc(RoadBehaviorAnalysis::getBehaviorTime));
        if (CollUtil.isEmpty(list)){
            return Collections.emptyList();
        }
        return list.stream().map(roadBehaviorAnalysis -> {
            RoadDangerBehaviorVO vo = new RoadDangerBehaviorVO();
            vo.setId(roadBehaviorAnalysis.getId());
            vo.setRecord(roadBehaviorAnalysis.getBehavior());
            vo.setRecordCode(roadBehaviorAnalysis.getBehaviorCode());
            vo.setRecordTime(roadBehaviorAnalysis.getBehaviorTime());
            vo.setRecordType(RoadBehaviorTypeEnum.getDescByCode(roadBehaviorAnalysis.getType()));
            vo.setRegion(roadBehaviorAnalysis.getRegion());
            vo.setPicturePath(roadBehaviorAnalysis.getPicturePath());
            vo.setOverspeedPositionInfo(roadBehaviorAnalysis.getOverspeedPositionInfo());
            vo.setIsWarn(roadBehaviorAnalysis.getIsWarn());
            vo.setIsHandled(roadBehaviorAnalysis.getIsHandled());
            return vo;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public String handleViolationRecord(RoadMonitorHandleReq req) {
        Long id = req.getId();
        // 获取危险行为数据
        RoadBehaviorAnalysis roadBehaviorAnalysis = roadBehaviorAnalysisService.getById(id);
        if (Objects.isNull(roadBehaviorAnalysis)){
            throw new BizException("数据不存在!");
        }
        if (Boolean.TRUE.equals(roadBehaviorAnalysis.getIsHandled())){
            throw new BizException("数据已处理!");
        }
        // 更新对应数据状态为已处理
        roadBehaviorAnalysis.setIsHandled(Boolean.TRUE);
        if (roadBehaviorAnalysisService.updateById(roadBehaviorAnalysis)) {
            return "处理成功!";
        }else {
            throw new BizException("处理失败!");
        }
    }

    public List<VehicleGpsDataVO> getVehicleGpsData(RoadMonitorReq req) {
        // TODO 暂时不确定隧道的经纬度范围 确定后 需要根据查询的隧道 筛选出对应经纬度范围内的GPS数据 目前返回全部的
        // 只查询最新的5分钟内的数据
        LocalDateTime startTime = LocalDateTime.now().minusMinutes(5);
        LocalDateTime endTime = LocalDateTime.now();
        List<NdDataAccessGps> data = dataAccessGpsService.list(Wrappers.lambdaQuery(NdDataAccessGps.class)
                .ge(NdDataAccessGps::getUpdateTime, startTime).le(NdDataAccessGps::getUpdateTime, endTime)
                .select(NdDataAccessGps::getCarLongitude, NdDataAccessGps::getCarLatitude, NdDataAccessGps::getCarPlate,
                        NdDataAccessGps::getCarVelocity, NdDataAccessGps::getCarDirection, NdDataAccessGps::getUpdateTime));
        log.info("最近5分钟 查询到{}条数据", data.size());
        // 如果最近15分钟没有数据(GPS数据不更新了) 取表中最新的5000条数据
        if (CollUtil.isEmpty(data)){
            data = dataAccessGpsService.list(Wrappers.lambdaQuery(NdDataAccessGps.class)
                     .select(NdDataAccessGps::getCarLongitude, NdDataAccessGps::getCarLatitude,
                             NdDataAccessGps::getCarPlate,NdDataAccessGps::getCarVelocity,
                             NdDataAccessGps::getCarDirection, NdDataAccessGps::getUpdateTime)
                    .orderByDesc(NdDataAccessGps::getUpdateTime).last("limit 5000"));
        }
        return data.stream().map(d -> {
            VehicleGpsDataVO vo = new VehicleGpsDataVO();
            vo.setCarPlate(d.getCarPlate());
            vo.setCarVelocity(d.getCarVelocity());
            vo.setCarDirection(d.getCarDirection());
            vo.setLongitude(d.getCarLongitude());
            vo.setLatitude(d.getCarLatitude());
            vo.setUpdateTime(d.getUpdateTime());
            return vo;
        }).collect(Collectors.toList());
    }

    public void pictureDownload(VideoDownloadReq req, HttpServletResponse response) {

        String picturePath = req.getPicturePath();
        // 将路径中的文件分割符替换为系统能够识别的分隔符
        picturePath = picturePath.replace("\\", File.separator);
        picturePath = picturePath.replace("/", File.separator);

        File file = new File(picturePath);

        // 设置文件名（将显示在下载对话框中）
        response.setHeader("Content-Disposition", "inline;");
        // 设置文件大小，这样浏览器可以显示下载进度
        response.setContentLengthLong(file.length());

        // 设置缓存控制头
        response.setHeader("Cache-Control", "public, max-age=31536000");

        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            ServletOutputStream servletOutputStream = response.getOutputStream();

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                servletOutputStream.write(buffer, 0, bytesRead);
            }
            fileInputStream.close();
            servletOutputStream.close();
        } catch (IOException e) {
            log.error("文件下载失败! {}",e.getMessage());
        }
    }

    public List<RoadScoreVO> getRealTimeComSitData(RoadMonitorReq req) {
        List<ComprehensiveSituation> roadScore = comprehensiveSituationService.list(Wrappers.lambdaQuery(ComprehensiveSituation.class)
                .eq(ComprehensiveSituation::getTunnel,req.getTunnel())
                .orderByDesc(ComprehensiveSituation::getCreateOn)
                .last("limit 60"));
        return roadScore.stream().map(p -> {
            RoadScoreVO roadScoreVO = new RoadScoreVO();
            BeanUtils.copyProperties(p, roadScoreVO);
            return roadScoreVO;
        }).collect(Collectors.toList())
                .stream()
                .sorted(Comparator.comparing(RoadScoreVO::getCreateOn))
                .collect(Collectors.toList());
    }

    public List<TrafficFlowVO> getRealTimeTrafficFlowData(RoadMonitorReq req) {
        List<TrafficFlow> trafficFlows = trafficFlowService.list(Wrappers.lambdaQuery(TrafficFlow.class)
                .in(TrafficFlow::getRegion, req.getRegionList())
                .orderByDesc(TrafficFlow::getCreateOn)
                .last("limit 12"));
        return trafficFlows.stream().map(p->{
            TrafficFlowVO trafficFlowVO = new TrafficFlowVO();
            BeanUtils.copyProperties(p,trafficFlowVO);
            return trafficFlowVO;
        }).collect(Collectors.toList())
                .stream()
                .sorted(Comparator.comparing(TrafficFlowVO::getCreateOn))
                .collect(Collectors.toList());
    }
}
