package com.gci.boot.modules.video.service.Impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gci.boot.common.util.JsonUtil;
import com.gci.boot.modules.basedata.entity.TbVehicle;
import com.gci.boot.modules.basedata.service.ITbVehicleService;
import com.gci.boot.modules.projects.service.IProjectsService;
import com.gci.boot.modules.system.service.ISysDictService;
import com.gci.boot.modules.system.vo.DictModel;
import com.gci.boot.modules.vehicles.mapper.TbViolationRecordMapper;
import com.gci.boot.modules.vehicles.vo.MessageVO;
import com.gci.boot.modules.vehicles.vo.VehicleProjectVO;
import com.gci.boot.modules.video.service.IVideoService;
import com.gci.boot.modules.video.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

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

@Service
@Slf4j
public class VideoServiceImpl implements IVideoService {

    @Value("${video.baseUrl}")
    private String baseUrl;
    @Value("${video.clientId}")
    private String clientId;
    @Value("${video.clientSecret}")
    private String clientSecret;
    @Value("${video.getTokenUrlSuffix}")
    private String getTokenUrlSuffix;
    @Value("${video.getDeviceListUrlSuffix}")
    private String getDeviceListUrlSuffix;
    @Value("${video.getDeviceUrlSuffix}")
    private String getDeviceUrlSuffix;
    @Value("${video.realPlayUrlSuffix}")
    private String realPlayUrlSuffix;
    @Value("${video.playBackUrlSuffix}")
    private String playBackUrlSuffix;
    @Value("${video.queryFilesAsyncUrlSuffix}")
    private String queryFilesAsyncUrlSuffix;
    @Value("${video.CutVideoUrlSuffix}")
    private String CutVideoUrlSuffix;
    @Value("${video.getCutVideoListUrlSuffix}")
    private String getCutVideoListUrlSuffix;
    @Value("${video.DownloadResourceUrlSuffix}")
    private String DownloadResourceUrlSuffix;
    @Autowired
    private ITbVehicleService vehicleService;
    @Autowired
    private TbViolationRecordMapper violationRecordMapper;
    @Autowired
    private ISysDictService sysDictService;
    @Autowired
    private IProjectsService projectsService;
    //码流类型 1-主码流 2-子码流
    private static final Integer BITTYPE = 2;

    @Override
    public String getVedioToken() {
        String url = baseUrl + getTokenUrlSuffix;
        Map<String, Object> param = new HashMap<>();
        param.put("grant_type", "client_credentials");
        param.put("scope", "video");
        param.put("client_id", clientId);
        param.put("client_secret", clientSecret);
        try {
            String body = HttpRequest.get(url).form(param).execute().body();
            Map<String,Object> bodyMap = JsonUtil.json2Map(body);
            return bodyMap.getOrDefault("access_token","").toString();
        }catch (Exception e){
            log.warn("获取视频云平台token失败：" + e.getMessage());
            throw new RuntimeException("获取视频云平台token失败!");
        }
    }

    @Override
    public List<VideoDeviceVO> getVideoDeviceList() {
        String token = getVedioToken();
        if(StrUtil.isBlank(token)){
            throw new RuntimeException("获取视频云平台token失败!");
        }
        String url = baseUrl + getDeviceListUrlSuffix;
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        Map<String, Object> param = new HashMap<>();
        param.put("pageNo", 1);
        param.put("pageSize", 1000);
        try {
            String body = HttpRequest.get(url).header(headers).form(param).execute().body();
            Map<String,Object> bodyMap = JsonUtil.json2Map(body);
            if ("200".equals(bodyMap.get("code").toString())) {
                List<VideoDeviceVO> videoDeviceVOList = JsonUtil.json2List(JsonUtil.object2JsonAllPretty(bodyMap.get("data")),VideoDeviceVO.class);
                return videoDeviceVOList;
            } else {
                log.warn("获取视频云平台所有的车辆列表失败：" + body);
                throw new RuntimeException("获取视频云平台所有的车辆列表!");
            }
        }catch (Exception e){
            log.warn("获取视频云平台所有的车辆列表失败：" + e.getMessage());
            throw new RuntimeException("获取视频云平台所有的车辆列表失败!");
        }
    }

    @Override
    public VideoDeviceVO getVideoDevice(String plateNo) {
        String token = getVedioToken();
        if(StrUtil.isBlank(token)){
            throw new RuntimeException("获取视频云平台token失败!");
        }
        String url = baseUrl + getDeviceUrlSuffix;
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        Map<String, Object> param = new HashMap<>();
        param.put("plateNo", plateNo);
        try {
            String body = HttpRequest.get(url).header(headers).form(param).execute().body();
            Map<String,Object> bodyMap = JsonUtil.json2Map(body);
            if ("200".equals(bodyMap.get("code").toString())) {
                VideoDeviceVO vo = JsonUtil.json2Object(JsonUtil.object2JsonAllPretty(bodyMap.get("data")),VideoDeviceVO.class);
                return vo;
            } else {
                log.warn("获取视频云平台设备失败：" + body);
                throw new RuntimeException("获取视频云平台设备失败!");
            }
        }catch (Exception e){
            log.warn("获取视频云平台设备失败：" + e.getMessage());
            throw new RuntimeException("获取视频云平台设备失败!");
        }
    }

    @Override
    public VideoPlayVO getRealPlay(String simNo, Integer channelNo) {
        String token = getVedioToken();
        if(StrUtil.isBlank(token)){
            throw new RuntimeException("获取视频云平台token失败!");
        }
        String url = baseUrl + realPlayUrlSuffix;
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        Map<String, Object> param = new HashMap<>();
        param.put("simNo", simNo);
        param.put("channel", channelNo);
        param.put("bitType", BITTYPE);
        try {
            String reqBody = JsonUtil.object2JsonAllPretty(param);
            String body = HttpRequest.post(url).header(headers).body(reqBody).execute().body();
            Map<String,Object> bodyMap = JsonUtil.json2Map(body);
            if ("200".equals(bodyMap.get("code").toString())) {
                VideoPlayVO result = new ObjectMapper().convertValue(bodyMap.get("data"), VideoPlayVO.class);;
                return result;
            } else {
                log.warn("获取设备视频云平台实时播放视频失败：" + body);
                throw new RuntimeException("获取设备视频云平台实时播放视频失败!");
            }
        }catch (Exception e){
            log.warn("获取设备视频云平台实时播放视频失败：" + e.getMessage());
            throw new RuntimeException("获取设备视频云平台实时播放视频失败!");
        }
    }

    @Override
    public VideoPlayVO getPlayBack(String simNo, Integer channelNo, String startTime, String endTime) {
        String token = getVedioToken();
        if(StrUtil.isBlank(token)){
            throw new RuntimeException("获取视频云平台token失败");
        }
        String url = baseUrl + playBackUrlSuffix;
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        Map<String, Object> param = new HashMap<>();
        param.put("simNo", simNo);
        param.put("channel", channelNo);
        param.put("startTime", startTime);
        param.put("endTime", endTime);
        param.put("bitType", 1);
        try {
            String reqBody = JsonUtil.object2JsonAllPretty(param);
            String body = HttpRequest.post(url).header(headers).body(reqBody).execute().body();
            Map<String,Object> bodyMap = JsonUtil.json2Map(body);
            if ("200".equals(bodyMap.get("code").toString())) {
                VideoPlayVO result = new ObjectMapper().convertValue(bodyMap.get("data"), VideoPlayVO.class);;
                return result;
            } else {
                log.warn("获取设备视频云平台历史回放失败：" + body);
                throw new RuntimeException("获取设备视频云平台历史回放失败!");
            }
        }catch (Exception e){
            log.warn("获取设备视频云平台历史回放失败：" + e.getMessage());
            throw new RuntimeException("获取设备视频云平台历史回放失败!");
        }
    }

    @Override
    public Object getFilesAsync(String simNo, Integer channelNo, String startTime, String endTime) {
        String token = getVedioToken();
        if(StrUtil.isBlank(token)){
            throw new RuntimeException("获取视频云平台token失败");
        }
        String url = baseUrl + queryFilesAsyncUrlSuffix;
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        Map<String, Object> param = new HashMap<>();
        param.put("simNo", simNo);
        param.put("channel", channelNo);
        param.put("startTime", startTime);
        param.put("endTime", endTime);
        try {
            String reqBody = JsonUtil.object2JsonAllPretty(param);
            String body = HttpRequest.post(url).header(headers).body(reqBody).execute().body();
            Map<String,Object> bodyMap = JsonUtil.json2Map(body);
            if ("200".equals(bodyMap.get("code").toString())) {
                return bodyMap.get("data");
            } else {
                log.warn("视频云平台文件查询（同步返回）失败：" + body);
                return null;
//                throw new RuntimeException("视频云平台文件查询（同步返回）失败!");
            }
        }catch (Exception e){
            log.warn("视频云平台文件查询（同步返回）失败：" + e.getMessage());
            throw new RuntimeException("视频云平台文件查询（同步返回）失败!");
        }
    }

    @Override
    public List<ResultDeviceVO> getDeviceList(String projectId,String id,Integer layer) {
        if(Objects.isNull(layer)){
            return buildProjectDevice();
        }
        if(layer == 1){
            return buildBrandDevice(id,layer);
        }
        if(layer == 2){
            return buildVehicleDevice(projectId,id,layer);
        }
        if(layer == 3){
            return buildChannelDevice(projectId,id,layer);
        }
        return null;
    }

    @Override
    public List<ResultDeviceVO> queryDeviceList(String plateNumber) {
        List<ResultDeviceVO> result = new ArrayList<>();
        LambdaQueryWrapper<TbVehicle> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TbVehicle::getCancelFlag,0).like(TbVehicle::getPlateNumber,plateNumber);
        List<TbVehicle> vehicleList = vehicleService.list(queryWrapper);
        List<String> plateNumberList = vehicleList.stream().map(TbVehicle::getPlateNumber).collect(Collectors.toList());

        List<VideoDeviceVO> videoDeviceVOList = getVideoDeviceList();
        videoDeviceVOList = videoDeviceVOList.stream().filter(item->plateNumberList.contains(item.getPlateNo())).collect(Collectors.toList());

        if(Objects.nonNull(videoDeviceVOList) && videoDeviceVOList.size()>0){
            videoDeviceVOList.stream().forEach(item->{
                ResultDeviceVO vo = new ResultDeviceVO();
                vo.setLayer(3);
                vo.setIsLeaf(false);
                vo.setId(item.getPlateNo());
                //项目
                List<TbVehicle> tempList = vehicleList.stream().filter(s->item.getPlateNo().equals(s.getPlateNumber())).collect(Collectors.toList());
                if(Objects.nonNull(tempList) && tempList.size()>0){
                    if(StrUtil.isBlank(tempList.get(0).getProjectId())){
                        vo.setProjectId("其它");
                    }else{
                        vo.setProjectId(tempList.get(0).getProjectId());
                    }
                }
                vo.setTitle(item.getPlateNo());
                vo.setOnline(item.getOnline());
                vo.setSimNo(item.getSimNo());
                vo.setChannelList(item.getChannelList());
                result.add(vo);
            });
        }

        List<String> inCloundplateNumberList = videoDeviceVOList.stream().map(VideoDeviceVO::getPlateNo).collect(Collectors.toList());
        List<TbVehicle> noInVehicleList = vehicleList.stream().filter(item->!(inCloundplateNumberList.contains(item.getPlateNumber()))).collect(Collectors.toList());
        noInVehicleList.stream().forEach(item->{
            ResultDeviceVO vo = new ResultDeviceVO();
            vo.setLayer(3);
            vo.setIsLeaf(false);
            vo.setId(item.getPlateNumber());
            //项目
            List<TbVehicle> tempList = vehicleList.stream().filter(s->item.getPlateNumber().equals(s.getPlateNumber())).collect(Collectors.toList());
            if(Objects.nonNull(tempList) && tempList.size()>0){
                if(StrUtil.isBlank(tempList.get(0).getProjectId())){
                    vo.setProjectId("其它");
                }else{
                    vo.setProjectId(tempList.get(0).getProjectId());
                }
            }
            vo.setTitle(item.getPlateNumber());
            vo.setOnline(false);
            vo.setSimNo(null);
            vo.setChannelList(null);
            result.add(vo);
        });
        return result;
    }

    @Override
    public int cutVideo(String sessionId,String startTime, String endTime) {
        //状态(-3离线 -7终端不存在 0正在执行 2加入等待队列)
        String token = getVedioToken();
        if(StrUtil.isBlank(token)){
            throw new RuntimeException("获取视频云平台token失败!");
        }
        if(StrUtil.isBlank(sessionId) || StrUtil.isBlank(startTime) || StrUtil.isBlank(endTime)){
            throw new RuntimeException("开始、结束时间及sessionId不能为空!");
        }
        //计算时间秒
        Date startDate = DateUtil.parse(startTime,"yyyy-MM-dd HH:mm:ss");
        Date endDate =  DateUtil.parse(endTime,"yyyy-MM-dd HH:mm:ss");
        long timeDifference = endDate.getTime() - startDate.getTime();
        int duration = (int) timeDifference / 1000;

        String url = baseUrl + CutVideoUrlSuffix;
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        Map<String, Object> param = new HashMap<>();
        param.put("duration", duration);
        param.put("playSessionId", sessionId);
        try {
            String reqBody = JsonUtil.object2JsonAllPretty(param);
            String body = HttpRequest.post(url).header(headers).body(reqBody).execute().body();
            Map<String,Object> bodyMap = JsonUtil.json2Map(body);
            if ("200".equals(bodyMap.get("code").toString())) {
                CutVideoResultVO result = new ObjectMapper().convertValue(bodyMap.get("data"), CutVideoResultVO.class);;
                return result.getStatus();
            } else {
                log.warn("视频云平台裁剪视频失败：" + body);
                throw new RuntimeException("视频云平台裁剪视频失败!");
            }
        }catch (Exception e){
            log.warn("视频云平台裁剪视频失败：" + e.getMessage());
            throw new RuntimeException("视频云平台裁剪视频失败!");
        }
    }

    @Override
    public CutVideoListPageVO getCutVideoList(int pageNo, int pageSize, String startTime, String endTime) {
        String token = getVedioToken();
        if(StrUtil.isBlank(token)){
            throw new RuntimeException("获取视频云平台token失败!");
        }
        String url = baseUrl + getCutVideoListUrlSuffix;
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(token);
        Map<String, Object> param = new HashMap<>();
        param.put("pageNo", pageNo);
        param.put("pageSize", pageSize);
        param.put("startTime", startTime);
        param.put("endTime", endTime);
        try {
            String body = HttpRequest.get(url).header(headers).form(param).execute().body();
            Map<String,Object> bodyMap = JsonUtil.json2Map(body);
            if ("200".equals(bodyMap.get("code").toString())) {
                CutVideoListPageVO vo = JsonUtil.json2Object(JsonUtil.object2JsonAllPretty(bodyMap.get("data")),CutVideoListPageVO.class);
                return vo;
            } else {
                log.warn("视频云平台获取裁剪视频任务信息列表失败:" + body);
                throw new RuntimeException("视频云平台获取裁剪视频任务信息列表失败!");
            }
        }catch (Exception e){
            log.warn("视频云平台获取裁剪视频任务信息列表失败:" + e.getMessage());
            throw new RuntimeException("视频云平台获取裁剪视频任务信息列表失败!");
        }
    }

    /**
     * 获取视频项目列表
     * @return
     */
    public List<ResultDeviceVO> buildProjectDevice(){

        List<ResultDeviceVO> result = new ArrayList<>();
        List<VehicleProjectVO> voList = violationRecordMapper.queryOtherVehicleProject();
        if(Objects.nonNull(voList) && voList.size()>0){
            voList.stream().forEach(item->{
                ResultDeviceVO vo = new ResultDeviceVO();
                vo.setLayer(1);
                vo.setIsLeaf(false);
                vo.setId(item.getProjectId());
                vo.setProjectId(item.getProjectId());
                vo.setTitle(item.getProjectName());
                result.add(vo);
            });
        }
        return result;
    }
    /**
     * 获取视频项目-->车辆品牌列表
     * @return
     */
    public List<ResultDeviceVO> buildBrandDevice(String id, Integer layer){
        List<ResultDeviceVO> result = new ArrayList<>();
        LambdaQueryWrapper<TbVehicle> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TbVehicle::getCancelFlag,0);
        if("其它".equals(id)){
            queryWrapper.and(wrapper -> wrapper.eq(TbVehicle::getProjectId,"")
                    .or().isNull(TbVehicle::getProjectId));
        }else {
            queryWrapper.eq(TbVehicle::getProjectId,id);
        }
        List<TbVehicle> vehicleList = vehicleService.list(queryWrapper);
        List<String> brandDictList = vehicleList.stream().map(TbVehicle::getVehicleBrand).collect(Collectors.toList());

        List<DictModel> dictModelList = sysDictService.queryDictItemsByCode("vehicle_brand");
        dictModelList = dictModelList.stream().filter(item->brandDictList.contains(item.getValue())).collect(Collectors.toList());
        if(Objects.nonNull(dictModelList) && dictModelList.size()>0){
            dictModelList.stream().forEach(item->{
                ResultDeviceVO vo = new ResultDeviceVO();
                vo.setLayer(layer+1);
                vo.setIsLeaf(false);
                vo.setId(item.getValue());
                vo.setProjectId(id);
                vo.setTitle(item.getText());
                vo.setParentId(id);
                result.add(vo);
            });
        }
        return result;
    }
    /**
     * 获取视频项目-->车辆品牌-->车牌列表
     * @return
     */
    public List<ResultDeviceVO> buildVehicleDevice(String projectId, String id, Integer layer){
        List<ResultDeviceVO> result = new ArrayList<>();
        LambdaQueryWrapper<TbVehicle> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TbVehicle::getCancelFlag,0).eq(TbVehicle::getVehicleBrand,id);
        if("其它".equals(projectId)){
            queryWrapper.and(wrapper -> wrapper.eq(TbVehicle::getProjectId,"")
                    .or().isNull(TbVehicle::getProjectId));
        }else {
            queryWrapper.eq(TbVehicle::getProjectId,projectId);
        }
        List<TbVehicle> vehicleList = vehicleService.list(queryWrapper);
        List<String> plateNumberList = vehicleList.stream().map(TbVehicle::getPlateNumber).collect(Collectors.toList());

        List<VideoDeviceVO> videoDeviceVOList = getVideoDeviceList();
        videoDeviceVOList = videoDeviceVOList.stream().filter(item->plateNumberList.contains(item.getPlateNo())).collect(Collectors.toList());

        if(Objects.nonNull(videoDeviceVOList) && videoDeviceVOList.size()>0){
            videoDeviceVOList.stream().forEach(item->{
                ResultDeviceVO vo = new ResultDeviceVO();
                vo.setLayer(layer+1);
                vo.setIsLeaf(false);
                vo.setId(item.getPlateNo());
                vo.setProjectId(projectId);
                vo.setTitle(item.getPlateNo());
                vo.setParentId(id);
                vo.setOnline(item.getOnline());
                vo.setSimNo(item.getSimNo());
                vo.setChannelList(item.getChannelList());
                result.add(vo);
            });
        }

        List<String> inCloundplateNumberList = videoDeviceVOList.stream().map(VideoDeviceVO::getPlateNo).collect(Collectors.toList());
        List<TbVehicle> noInVehicleList = vehicleList.stream().filter(item->!(inCloundplateNumberList.contains(item.getPlateNumber()))).collect(Collectors.toList());
        noInVehicleList.stream().forEach(item->{
            ResultDeviceVO vo = new ResultDeviceVO();
            vo.setLayer(layer+1);
            vo.setIsLeaf(false);
            vo.setId(item.getPlateNumber());
            vo.setProjectId(projectId);
            vo.setTitle(item.getPlateNumber());
            vo.setParentId(id);
            vo.setOnline(false);
            vo.setSimNo(null);
            vo.setChannelList(null);
            result.add(vo);
        });

        return result;
    }
    /**
     * 获取视频项目-->车辆品牌-->车牌-->视频通道列表
     * @return
     */
    public List<ResultDeviceVO> buildChannelDevice(String projectId, String id, Integer layer){
        List<ResultDeviceVO> result = new ArrayList<>();
        VideoDeviceVO vo = getVideoDevice(id);
        if(Objects.nonNull(vo)){
            for(ChannelVO channelVO : vo.getChannelList()){
                ResultDeviceVO one = new ResultDeviceVO();
                one.setLayer(layer+1);
                one.setIsLeaf(true);
                one.setId(channelVO.getChannelNo().toString());
                one.setProjectId(projectId);
                one.setTitle(channelVO.getChannelName());
                one.setParentId(id);
                one.setOnline(vo.getOnline());
                one.setSimNo(vo.getSimNo());
                one.setChannelNo(channelVO.getChannelNo());
                result.add(one);
            }
        }
        return result;
    }
}
