package com.ozs.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.ozs.common.config.BaseConfig;
import com.ozs.common.constant.Constants;
import com.ozs.common.core.domain.AjaxResult;
import com.ozs.common.core.domain.entity.SysDictData;
import com.ozs.common.core.redis.RedisCache;
import com.ozs.common.exception.base.BaseException;
import com.ozs.common.utils.DateUtils;
import com.ozs.common.utils.HttpClientUtil;
import com.ozs.common.utils.http.HttpUtils;
import com.ozs.entity.BaseCameraManagement;
import com.ozs.entity.BaseTerminal;
import com.ozs.entity.BaseTerminalLog;
import com.ozs.entity.MsgHeartbeatAlarmMessage;
import com.ozs.entity.response.BaseCameraManagementResponse;
import com.ozs.entity.vo.CamerasVo;
import com.ozs.entity.vo.PlaybackVo;
import com.ozs.framework.config.ServerConfig;
import com.ozs.service.BaseCameraManagementService;
import com.ozs.service.BaseTerminalLogService;
import com.ozs.service.BaseTerminalService;
import com.ozs.service.MsgHeartbeatAlarmMessageService;
import com.ozs.system.mapper.SysDictDataMapper;
import com.ozs.system.service.ISysDictTypeService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

/**
 * 相机工具
 */

@Configuration
@Slf4j
public class CameraUtil {
    private static final ExecutorService executor = Executors.newFixedThreadPool(20);

    private static String historyUrl;
    private static String ffmpegPath;
    private static String filePath;
    private static String transcribeFilePath;
    private static String webUrl;
    private static String bakUrl;
    private static String bakUrlRtsp;
    private static String wsUrl;
    private static CmdCameraUtil cUtil;
    private static RedisCache rc;
    private static ServerConfig sc;
    private static String recordUrl;
    private static String hkUrl;
    private static String host;
    private static String appKey;
    private static String appSecret;
    private static String rtmpUrl;

    @Autowired
    private CaneraConfig caneraConfig;

    @Autowired
    private CmdCameraUtil cmdCameraUtil;

    @Autowired
    private SysDictDataMapper dictDataMapper;

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ServerConfig serverConfig;
    @Autowired
    private BaseTerminalService baseTerminalService;
    @Autowired
    private MsgHeartbeatAlarmMessageService msgHeartbeatAlarmMessageService;
    @Autowired
    private ISysDictTypeService dictTypeService;
    @Autowired
    private RtspToMP4 rtspToMP4;
    @Resource
    BaseCameraManagementService baseCameraManagementService;

    @Resource
    private BaseTerminalLogService baseTerminalLogService;

    private Map<String, Process> map = new HashMap<>();

    public final static String tsFilekey = "mergeVideoTsFile";


    /**
     * 历史回放
     *
     * @param fromVideoFileList
     * @param ph
     * @return
     * @throws IOException
     */
    public static String historyPlay(List<String> fromVideoFileList, String ph, boolean flay) {
        // 视频服务映射路径
        String NewfilePath = BaseConfig.getProfile() + "/" + ph;
        log.info("NewfilePath:{}", NewfilePath);
        log.info("fromVideoFileList:{}", fromVideoFileList);
        if (ObjectUtils.isEmpty(fromVideoFileList) || fromVideoFileList.size() <= 0) {
            throw new BaseException("当前相机无视频录像");
        }
        executor.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    txConvetor(fromVideoFileList, NewfilePath, flay);
                } catch (IOException e) {
                    log.error(e.getMessage());
                    e.printStackTrace();
                }
            }
        });
//        executor.shutdown();

        return Constants.RESOURCE_PREFIX + "/" + ph;
    }


    @SneakyThrows
    public static void txConvetor(List<String> fromVideoFileList,
                                  String newfilePath,
                                  boolean fly) throws IOException {
        /*
        * ffmpeg -i 20230411_155847_155947-d4c2265d-d83e-11ed-8e7f-fa163e4e1e9f.flv -c:v copy 1.ts
ffmpeg -i 20230411_155948_160048-f91fea03-d83e-11ed-8e7f-fa163e4e1e9f.flv -c:v copy 2.ts
ffmpeg -i "concat:1.ts|2.ts" -c copy output.mp4
        * */

        File file = new File(newfilePath);
        boolean flay = false;
        if (!file.getParentFile().exists()) {
            boolean mkdirs = file.getParentFile().mkdirs();
            log.info("创建文件夹：{}", file.getParentFile().getPath());
            log.info("创建文件夹结果：{}", mkdirs);
            flay = true;
        }
        cUtil.cmd("chomd -R 777 " + file.getParentFile().getPath());
        log.info("newfilePath：{}", newfilePath);
        StringBuffer sm = new StringBuffer(ffmpegPath + " -i \"concat:");
        List<String> fileTs = new ArrayList<>();
        for (int t = 0; t < fromVideoFileList.size(); t++) {
            File ft = new File(fromVideoFileList.get(t));
            if (ft.exists()) {
                log.info("file:{}", fromVideoFileList.get(t));
                String substring = fromVideoFileList.get(t).substring(0, fromVideoFileList.get(t).lastIndexOf("."));
                int x;//定义两变量
                Random ne = new Random();//实例化一个random的对象ne
                x = ne.nextInt(9999 - 1000 + 1) + 1000;//为变量赋随机值1000-9999
                substring = substring + x;//定义两变量

                String cmdstr = ffmpegPath + " -i " + fromVideoFileList.get(t) + " -c:v copy " + substring + ".ts";
                log.info("转换命令：{}", cmdstr);
                cUtil.cmd(cmdstr);
                fileTs.add(substring + ".ts");
                if (t != fromVideoFileList.size() - 1) {
                    sm.append(substring + ".ts|");
                } else {
                    sm.append(substring + ".ts\" ");
                }
            }
        }

        if (fileTs.size() > 0) {
            Map<String, Object> mergeVideoTsFile = rc.getCacheMap(tsFilekey);
            if (ObjectUtils.isEmpty(mergeVideoTsFile)) {
                mergeVideoTsFile = new HashMap<>();
            }
            if (!flay) {
                // 如果没有解除，把生成的文件放入要删除的定时任务 redis key 中
                fileTs.add(newfilePath);
            }
            mergeVideoTsFile.put(System.currentTimeMillis() + "", fileTs);
            rc.deleteObject(tsFilekey);
            if (mergeVideoTsFile.size() > 0) {
                rc.setCacheMap(tsFilekey, mergeVideoTsFile);
            }

            sm.append("-c copy " + newfilePath);
            log.info("合并命令：{}", sm.toString());
            cUtil.cmd(sm.toString());
        }

    }

    /**
     * 实时播放的拼接流
     *
     * @param cameraCode 相机编码
     * @param channel    相机通道
     * @return
     */
    public static String getPlayFlv(String cameraCode, String channel, boolean flay) {
        if (!flay) {
            return wsUrl + "/ws/" + cameraCode + "/" + channel + ".flv";
        }
        return wsUrl + "/ws/" + cameraCode + "/" + channel + ".flv";


//        if (!flay) {
//            return bakUrl + "/ws/" + channel + "/" + cameraCode + ".flv";
//        }
//        return webUrl + "/ws/" + channel + "/" + cameraCode + ".flv";
    }


    /**
     * Rtsp实时播放的拼接流
     *
     * @param cameraCode 相机编码
     * @param channel    相机通道
     * @return
     */
    public static String getPlayFlvRtsp(String cameraCode, String channel, boolean flay) {
        if (!flay) {
            return webUrl + "/" + channel + "/" + cameraCode;
        }
        return webUrl + "/" + channel + "/" + cameraCode;


//        if (!flay) {
//            return bakUrl + "/ws/" + channel + "/" + cameraCode + ".flv";
//        }
//        return webUrl + "/ws/" + channel + "/" + cameraCode + ".flv";
    }

    /**
     * web页面实时流接口
     *
     * @param cameraCode
     * @param channel
     * @return
     */
    public static String getPlayFlv(String cameraCode, String channel) {
//        List<String> pathList = new ArrayList<>();
//        String data = HttpUtils.sendGet(webUrl + "/rtsp/api/list");
//        if (StringUtils.isNotEmpty(data)) {
//            JSONArray jsonArray = JSONArray.parseArray(data);
//            for (int i = 0; i < jsonArray.size(); i++) {
//                JSONObject jsonObject = jsonArray.getJSONObject(i);
//                String name = jsonObject.getString("Path");
//                pathList.add(name);
//            }
//            boolean contains = pathList.contains(cameraCode + "/" + channel);
//            if (contains) {
//                return getPlayFlv(cameraCode, channel, true);
//            } else {
//                /**
//                 *  jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006");
//                 *         jsonBody.put("streamType", 0);
//                 *         jsonBody.put("protocol","rtsp");
//                 *         jsonBody.put("transmode", 1);
//                 *         jsonBody.put("expand","streamform=rtp");
//                 */
//                CamerasVo camerasVo = new CamerasVo();
//                camerasVo.setCameraIndexCode(cameraCode);
//                camerasVo.setStreamType(0);
//                camerasVo.setTransmode(1);
//                camerasVo.setProtocol("rtsp");
//                camerasVo.setExpand("streamform=rtp");
//                previewURLs(camerasVo, channel);
//                return getPlayFlv(cameraCode, channel, true);
//            }
//        } else {
//            return "流媒体目前没有RTSP协议的流";
//        }
        return getPlayFlv(cameraCode, channel, true);
    }

    public static String invite(String cameraCode, String channel) {
        String result = null;
        String url = bakUrl + "/api/gb28181/invite?id=" + cameraCode + "&channel=" + channel;
        try {
            Response response = HttpClientUtil.get(url);
            log.info("result：{}", String.valueOf(response.code()));
            return String.valueOf(response.code());
        } catch (Exception e) {
            log.info(e.getMessage());
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 开启录制功能
     *
     * @param cameraCode 相机编码
     * @param channel    相机通道
     * @return
     */
    public static String startRecording(String cameraCode, String channel) {
        return historyUrl + "/recordpro/api/start?streamPath=" + channel + "/" + cameraCode;
    }

    /**
     * 关闭录制功能
     *
     * @param taskId 录像接口返回的任务ID
     * @return
     */
    public static String endRecording(String taskId) {
        return historyUrl + "/recordpro/api/stop?id=" + taskId;
    }


    /**
     * 历史回放流（获取）
     *
     * @param channel 相机通道
     * @param startTm 开始时间
     * @param endTm   结束时间
     * @return
     */
    public static String historyPlayListStr(String channel, Date startTm, Date endTm, boolean flay) {
        List<String> list = filterPlayList(channel, startTm, endTm, filePath);
        String uuid = UUID.randomUUID().toString();
        String ph = "record/flv/" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, new Date())
                + "/" + channel + "/"
                + uuid + ".mp4";
        if (!ObjectUtils.isEmpty(list)) {
            try {
                return historyPlay(list, ph, flay);
            } catch (Exception e) {
                log.error(e.getMessage());
                e.printStackTrace();
            }
        } else {
            throw new BaseException("当前相机无视频录像");
        }
        return null;
    }


    /**
     * 过滤符合条件的视频
     *
     * @param channel
     * @param startTm
     * @param endTm
     * @param mappingUrl
     * @return
     */
    public static List<String> filterPlayList(String channel, Date startTm, Date endTm, String mappingUrl) {
        if (StringUtils.isBlank(channel)
                || ObjectUtils.isEmpty(startTm)
                || ObjectUtils.isEmpty(endTm)) {
            return null;
        }

        List<String> ls = new ArrayList<>();
        Map<Date, String> m = new HashMap<>();
        // 调用视频服务返回参数
        String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTm);
        String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, endTm);

        String param = "channel=" + channel + "&startTime=" + startTime + "&endTime=" + endTime;
        String s = HttpUtils.sendGet(historyUrl + "/api/record/flv/list", param);
        // 视频拼接
        if (!StringUtils.isBlank(s) && !"null".equals(s) && !s.startsWith("<!DOCTYPE html>")) {
            List<Map<String, Object>> maps = JSON.parseArray(s, Map.class);
            if (ObjectUtils.isEmpty(maps)) {
                return null;
            }
            for (Map<String, Object> map : maps) {
                Object path = map.get("Path");
                if (!ObjectUtils.isEmpty(path)) {
                    String s1 = path.toString();
                    String substring = s1.substring(s1.lastIndexOf("/") + 1, s1.length());
                    String substring1 = substring.substring(0, substring.indexOf("-"));
                    String[] s2 = substring1.split("_");
                    if (!ObjectUtils.isEmpty(s2)) {

                        String s3 = s2[0] + s2[1];
                        String s4 = s2[0] + s2[2];
                        Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s3);
                        if (s2[1].startsWith("23") && s2[2].startsWith("00")) {
                            sdate = DateUtils.addDays(sdate, -1);
                        }
                        Date edate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s4);
                        /*     sdate  |startTm|  edate     |endTm| */
                        if (startTm.compareTo(sdate) >= 0
                                && startTm.compareTo(edate) <= 0
                                && endTm.compareTo(edate) >= 0) {
                            m.put(sdate, mappingUrl + path.toString());
                            /*  |startTm|   sdate    edate   |endTm| */
                        } else if (startTm.compareTo(sdate) <= 0 && endTm.compareTo(edate) >= 0) {
                            m.put(sdate, mappingUrl + path.toString());

                            /*  |startTm|   sdate     |endTm|  edate  */
                        } else if (startTm.compareTo(sdate) <= 0
                                && endTm.compareTo(sdate) >= 0
                                && endTm.compareTo(edate) <= 0) {
                            m.put(sdate, mappingUrl + path.toString());

                            /*  sdate |startTm|      |endTm| edate  */
                        } else if (startTm.compareTo(sdate) >= 0 && endTm.compareTo(edate) <= 0) {
                            m.put(sdate, mappingUrl + path.toString());
                        }
                    }
                }
            }
        }
        if (!ObjectUtils.isEmpty(m) && m.size() > 0) {
            Set<Date> dates = m.keySet();
            // 排序
            dates.stream().parallel().collect(Collectors.toList()).stream().sorted().forEach(d -> {
                ls.add(m.get(d));
            });
            return ls;
        }
        return null;
    }

    /**
     * 合并视频（转化文件）
     *
     * @param fromVideoFileList 视频路径
     * @param newfilePath       生产新的视频文件路径
     * @throws IOException
     */
    public static Map<String, String> myConvetor(List<String> fromVideoFileList,
                                                 String newfilePath,
                                                 String uuid) throws IOException {
        /*
        * for f in *.flv; do echo "file '$f'" >> mylist.txt; done
            ffmpeg -f concat -i mylist.txt -c copy output.flv
        * */

        File file = new File(newfilePath);
        boolean flay = false;
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
            log.info("创建文件夹：{}", file.getParentFile().getPath());
            flay = true;
        }
        log.info("newfilePath：{}", newfilePath);


        StringBuffer sm = new StringBuffer("for f in ");
        String pathStr = null;
        for (int t = 0; t < fromVideoFileList.size(); t++) {
            File ft = new File(fromVideoFileList.get(t));
            if (ft.exists()) {
                if (t != fromVideoFileList.size() - 1) {
//                    sm.append(fromVideoFileList.get(t) + " ");
                    sm.append(fromVideoFileList.get(t).substring(fromVideoFileList.get(t).lastIndexOf("/") + 1, fromVideoFileList.get(t).length()) + " ");
                } else {
//                    sm.append(fromVideoFileList.get(t));
                    sm.append(fromVideoFileList.get(t).substring(fromVideoFileList.get(t).lastIndexOf("/") + 1, fromVideoFileList.get(t).length()));
                    pathStr = fromVideoFileList.get(t).substring(0, fromVideoFileList.get(t).lastIndexOf("/"));
                }
            }
        }
//        String substring = newfilePath.substring(0, newfilePath.lastIndexOf("."));
//        substring = substring + ".txt";

        String substring = uuid + ".txt";
        log.info("临时转化的文件：{}", substring);


        sm.append("; do echo \"file '$f'\" >> " + substring + "; done");
        String commit = sm.toString();
        log.info("合并转化文件的命令：{}", commit);
        Process proc = Runtime.getRuntime().exec("/bin/bash", null, null);
        BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);

        try {
            String commit1 = ffmpegPath + " -f concat -safe 0 -i " + pathStr + "/" + substring + " -c copy " + newfilePath;

            log.info("合并视频命令：{}", commit1);
            List<String> commands = new ArrayList<>();
            if (flay) {
                commands.add("chomd -R 777 " + file.getParentFile().getPath());
            }
            //
            commands.add("cd " + pathStr);
            // 合并成一个临时文件
            commands.add(commit);

            // 临时文件转化为 flv
//            commands.add(commit1);
            log.info("录像视频命令：{}", commands);
            for (String line : commands) {
                log.info("命令：{}", line);
                out.println(line);
            }
            out.println("exit");// 这个命令必须执行，否则in流不结束。
            log.info("命令：{}", "exit");
            String rspLine = "";
            while ((rspLine = in.readLine()) != null) {
                log.info("*****:{}", rspLine);
            }
            proc.waitFor();
            Map<String, String> map = new HashMap<>();
            map.put("cmd", commit1);
            map.put("path", pathStr + "/" + substring);
            return map;


        } catch (InterruptedException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        } finally {
            in.close();
            out.close();
            proc.destroy();
        }
        return null;
    }

    /**
     * web页面视频回放接口
     *
     * @param code
     * @param startTm
     * @param endTm
     * @return
     */
    public static String getRecordList(String code, Date startTm, Date endTm) {
        PlaybackVo playbackVo = new PlaybackVo();
        playbackVo.setCameraIndexCode(code);
        // 格式化时间
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        playbackVo.setBeginTime(dateFormat.format(startTm));
        playbackVo.setEndTime(dateFormat.format(endTm));
        playbackVo.setProtocol("ws");
        //对象转换json字符串
        String body = JSONObject.toJSONString(playbackVo);
        //调用天网接口
        String playbackURLs = getPreviewURLs("/api/video/v1/cameras/playbackURLs", body);
        JSONObject outJson = (JSONObject) JSONObject.parse(playbackURLs);
        log.info("outJson-------->" + outJson);
        if ("0".equals(outJson.getString("code"))) {
            JSONObject data = outJson.getJSONObject("data");
            String urls = data.getString("url");
            return urls;
        } else {
            return "调用天网接口失败";
        }
//        return filterRecordList(channel, startTm, endTm, filePath, recordUrl + "profile/");
    }

    /**
     * 定时任务参数flv文件
     *
     * @throws IOException
     * @throws InterruptedException
     */
    public void deleteFlv() throws IOException, InterruptedException {
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, -1); //把日期往后增加一天,整数  往后推,负数往前移动
        date = calendar.getTime(); //这个时间就是日期往后推一天的结果
        String path = BaseConfig.getProfile() + "/flv/" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, date);
        File file = new File(path);
        if (file.exists()) {
            List<String> rspList = new ArrayList<String>();
            Process proc = Runtime.getRuntime().exec("/bin/bash", null, null);
            BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
            String commit = " rm -rf  " + path;
            List<String> commands = new ArrayList<>();

            // 删除
            commands.add(commit);
            log.info("删除昨天的录像视频命令：{}", commands);
            for (String line : commands) {
                out.println(line);
            }
            out.println("exit");// 这个命令必须执行，否则in流不结束。
            String rspLine = "";
            while ((rspLine = in.readLine()) != null) {
                System.out.println(rspLine);
                rspList.add(rspLine);
            }
            int i = proc.waitFor();
            log.info("执行结果：{}", i);

            in.close();
            out.close();
            proc.destroy();
        }
    }


    /**
     * 定时任务：删除超过配置时长的录制视频
     *
     * @throws IOException
     * @throws InterruptedException
     */
    public void deleteFlvExceed() throws IOException, InterruptedException, ParseException {
        //字典中设置的值
        List<SysDictData> sysCameraRecordTime = dictDataMapper.selectDictDataByType("sys_camera_record_time");

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        //正数，日期天数加
        //负数，日期天数减                         提前45天
        if (!ObjectUtils.isEmpty(sysCameraRecordTime)) {
            String dictValue = sysCameraRecordTime.get(0).getDictValue();
            calendar.add(Calendar.DAY_OF_YEAR, Integer.parseInt("-" + dictValue));
        } else {
            calendar.add(Calendar.DAY_OF_YEAR, -45);
        }
        date = calendar.getTime();

        //遍历每个进行视频录制的摄像头
        File file = new File(transcribeFilePath);
        log.info("file.Name()======================================" + file.getName());
        log.info("file.exists()======================================" + file.exists());
        if (file.exists() && file.isDirectory()) {
            //获取文件夹中所有的子文件夹和文件
            File[] files = file.listFiles();
            if (!ObjectUtils.isEmpty(files) && files.length > 0) {
                for (File file1 : files) {
                    //   file1=/opt/streams/record/flv/34020000001320000167
                    log.info("file1.Name()======================================" + file1.getName());
                    if (file1.exists() && file1.isDirectory()) {
                        //相机文件
                        File[] fs = file1.listFiles();
                        if (!ObjectUtils.isEmpty(fs) && fs.length > 0) {
                            for (File f : fs) {
                                //    f=/opt/streams/record/flv/34020000001320000167/20230328_192033_192037-91509173-cd5a-11ed-8a42-fa163e4e1e9f.flv
                                //fName=20230328_192033_192037-91509173-cd5a-11ed-8a42-fa163e4e1e9f.flv
                                String fName = f.getName();
                                log.info("fName======================================" + fName);
                                String[] split = fName.split("_");
                                if (split.length > 0) {
                                    //20230328
                                    String s = split[0];
                                    Date parse = sdf.parse(s);
                                    long fTime = parse.getTime();
                                    long dateTime = date.getTime();
                                    //删除过期文件
                                    if (fTime < dateTime) {
                                        f.delete();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }


    public static File[] getCurFilesList(String filePath) {
        File path = new File(filePath);
        File[] listFiles = path.listFiles(new FileFilter() {

            @Override
            public boolean accept(File pathname) {
                if (pathname.isFile()) {
                    return true;
                } else {

                    return false;
                }
            }
        });

        return listFiles;
    }

    public static void execute(String command) {
        try {
            ProcessBuilder process = new ProcessBuilder(command);
            process.inheritIO().start().waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * web页面实时流调用的远程天网接口
     *
     * @param camerasVo
     * @param channel
     */
    public static void previewURLs(CamerasVo camerasVo, String channel) {
        /**
         *  jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006");
         *         jsonBody.put("streamType", 0);
         *         jsonBody.put("protocol","rtsp");
         *         jsonBody.put("transmode", 1);
         *         jsonBody.put("expand","streamform=rtp");
         */
        camerasVo.setStreamType(0);
        camerasVo.setProtocol("rtsp");
        camerasVo.setTransmode(1);
        camerasVo.setExpand("streamform=rtp");
        String body = JSONObject.toJSONString(camerasVo);
        String previewURLs = getPreviewURLs("/api/video/v1/cameras/previewURLs", body);
        log.info("-------------------------------->>>>>previewURLs" + previewURLs);
        JSONObject outJson = JSONObject.parse(previewURLs);
        if ("0".equals(outJson.getString("code"))) {
            log.info("outJson----->" + outJson);
            JSONObject data = outJson.getJSONObject("data");
            String urls = data.getString("url");
            HttpUtils.sendGet(historyUrl + "rtsp/api/pull?target=" + urls + "&streamPath=" + camerasVo.getCameraIndexCode() + "/" + channel + "&save=0");
        }
    }

    @PostConstruct
    public void init() {
        historyUrl = caneraConfig.getHistoryUrl();
        ffmpegPath = caneraConfig.getFfmpegPath();
        filePath = caneraConfig.getFilePath();
        transcribeFilePath = caneraConfig.getTranscribeFilePath();
        webUrl = caneraConfig.getWebUrl();
        bakUrl = caneraConfig.getBakUrl();
        bakUrlRtsp = caneraConfig.getBakUrlRtsp();
        rc = redisCache;
        cUtil = cmdCameraUtil;
        sc = serverConfig;
        wsUrl = caneraConfig.getWsUrl();
        recordUrl = caneraConfig.getRecordUrl();
        hkUrl = caneraConfig.getHkUrl();
        host = caneraConfig.getHost();
        appKey = caneraConfig.getAppKey();
        appSecret = caneraConfig.getAppSecret();
        rtmpUrl = caneraConfig.getRtmpUrl();
    }

    /**
     * HTTP流转RTSP流
     */
    public String streamConversion(String code) {

        ExecutorService executor = Executors.newSingleThreadExecutor();
        Callable<String> task = new Callable<String>() {
            @Override
            public String call() throws Exception {
                // 执行网络请求...
                log.info(ffmpegPath + " -re -i /opt/streams/compress/" + code + ".mp4  -c:v copy -c:a copy -f flv " + rtmpUrl + "/live/" + code);
                cmdCameraUtil.cmd(ffmpegPath + " -re -i /opt/streams/compress/" + code + ".mp4  -c:v copy -c:a copy -f flv " + rtmpUrl + "/live/" + code);
                return "Response";
            }
        };

        try {
            String result = executor.submit(task).get(1, TimeUnit.SECONDS); // 设置5秒超时时间
            System.out.println("Response: " + result);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            // 请求超时处理逻辑
            System.out.println("Request timeout");
        }

        executor.shutdown();
        return bakUrlRtsp + "/live/" + code;
    }


    public static List<Map<String, Object>> filterRecordList(String channel,
                                                             Date startTm,
                                                             Date endTm,
                                                             String mappingUrl,
                                                             String wUrl) {
        List<Map<String, Object>> rmaps = new ArrayList<>();

        if (StringUtils.isBlank(channel)
                || ObjectUtils.isEmpty(startTm)
                || ObjectUtils.isEmpty(endTm)) {
            return null;
        }
        Map<Date, Map<String, Object>> m = new HashMap<>();
        // 调用视频服务返回参数
        String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTm);
        String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, endTm);

        String param = "channel=" + channel + "&startTime=" + startTime + "&endTime=" + endTime;
        // /api/record/flv/list
        String s = HttpUtils.sendGet(webUrl + "/recordpro/api/list", param);
        // 视频拼接
        if (!StringUtils.isBlank(s) || "null".equals(s)) {
            List<Map<String, Object>> maps = JSON.parseArray(s, Map.class);
            if (ObjectUtils.isEmpty(maps)) {
                return null;
            }
            for (Map<String, Object> map : maps) {
                Object path = map.get("Path");
                Object size = map.get("Size");
                Object duration = map.get("Duration");
                if (!ObjectUtils.isEmpty(path)) {
                    String s1 = path.toString();
                    String substring = s1.substring(s1.lastIndexOf("/") + 1, s1.length());
                    String substring1 = substring.substring(0, substring.indexOf("-"));
                    String[] s2 = substring1.split("_");
                    if (!ObjectUtils.isEmpty(s2)) {
                        Map<String, Object> mo = new HashMap<>();

                        String s3 = s2[0] + s2[1];
                        String s4 = s2[0] + s2[2];
                        Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s3);
                        if (s2[1].startsWith("23") && s2[2].startsWith("00")) {
                            sdate = DateUtils.addDays(sdate, -1);
                        }
                        Date edate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s4);
                        mo.put("startTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, sdate));
                        mo.put("entTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, edate));
                        mo.put("url", wUrl + path.toString());
                        mo.put("path", mappingUrl + path.toString());
                        mo.put("fileName", substring);
                        mo.put("size", size);
                        mo.put("duration", duration);
                        /*     sdate  |startTm|  edate     |endTm| */
                        if (startTm.compareTo(sdate) >= 0
                                && startTm.compareTo(edate) <= 0
                                && endTm.compareTo(edate) >= 0) {
                            m.put(sdate, mo);
                            /*  |startTm|   sdate    edate   |endTm| */
                        } else if (startTm.compareTo(sdate) <= 0 && endTm.compareTo(edate) >= 0) {
                            m.put(sdate, mo);

                            /*  |startTm|   sdate     |endTm|  edate  */
                        } else if (startTm.compareTo(sdate) <= 0
                                && endTm.compareTo(sdate) >= 0
                                && endTm.compareTo(edate) <= 0) {
                            m.put(sdate, mo);

                            /*  sdate |startTm|      |endTm| edate  */
                        } else if (startTm.compareTo(sdate) >= 0 && endTm.compareTo(edate) <= 0) {
                            m.put(sdate, mo);
                        }
                    }
                }
            }
        }
        if (!ObjectUtils.isEmpty(m) && m.size() > 0) {
            Set<Date> dates = m.keySet();
            // 排序
            dates.stream().parallel().collect(Collectors.toList()).stream().sorted().forEach(d -> {

                rmaps.add(m.get(d));
            });
            log.info("rmaps:{}", rmaps);
            return rmaps;
        }
        return null;
    }

    /**
     * 机车状态修改
     */
    public void heartbeat() {
        List<BaseTerminal> list = baseTerminalService.list();
        for (BaseTerminal baseTerminal : list) {
            QueryWrapper<BaseTerminalLog> wrapper = new QueryWrapper<>();
            wrapper.eq("terminal_code", baseTerminal);
            wrapper.orderByDesc("create_time");
            wrapper.last("limit 1");
            BaseTerminalLog baseTerminalLog = baseTerminalLogService.getOne(wrapper);
            if (ObjectUtils.isEmpty(baseTerminalLog)) {
                baseTerminal.setStatus(2);
                baseTerminalService.updateById(baseTerminal);
            } else {
                List<SysDictData> heartbeat = dictTypeService.selectDictDataByType("heartbeat");
                long timeNow = System.currentTimeMillis();
                long createTime = baseTerminalLog.getCreateTime().getTime();
                int times = Integer.parseInt(heartbeat.get(0).getDictValue());
                long thereHourMillis = 60 * 1000 * 3 * times;
                long timeNew = timeNow - thereHourMillis;
                if (timeNew > createTime) {
                    baseTerminal.setStatus(2);
                    baseTerminalService.updateById(baseTerminal);
                } else {
                    baseTerminal.setStatus(1);
                    baseTerminalService.updateById(baseTerminal);
                }
            }
        }

    }

    /**
     * 天网接口
     *
     * @return
     */
    public static String getPreviewURLs(String url, String body) {

        /**
         * STEP1：设置平台参数，根据实际情况,设置host appkey appsecret 三个参数.
         */
        ArtemisConfig.host = host; // 平台的ip端口
        ArtemisConfig.appKey = appKey;  // 密钥appkey
        ArtemisConfig.appSecret = appSecret;// 密钥appSecret

        /**
         * STEP2：设置OpenAPI接口的上下文
         */
        final String ARTEMIS_PATH = "/artemis";

        /**
         * STEP3：设置接口的URI地址
         */
        final String previewURLsApi = ARTEMIS_PATH + url;
        Map<String, String> path = new HashMap<String, String>(2) {
            {
                put("https://", previewURLsApi);//根据现场环境部署确认是http还是https
            }
        };

        /**
         * STEP4：设置参数提交方式
         */
        String contentType = "application/json";


        /**
         * STEP6：调用接口
         */
        String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType, null);// post请求application/json类型参数
        log.info("GetCameraPreviewURL----->" + result);
        return result;
    }

    /**
     * RTSP流视频压缩
     */
    public void videoCompression(String code) {
        // 执行网络请求...
        log.info(ffmpegPath + " -i /opt/streams/map/" + code + ".mp4 -c:v libx264 -s 640x480 -c:a adpcm_swf -ar 44100 /opt/streams/compress/" + code + ".mp4");
        cmdCameraUtil.cmd(ffmpegPath + " -i /opt/streams/map/" + code + ".mp4 -c:v libx264 -s 640x480 -c:a adpcm_swf -ar 44100 /opt/streams/compress/" + code + ".mp4");
    }

//    public  String stopStream(String cameraIndexCode, String channel) {
//        try {
//            log.info("code---------->" + httpUrl + "/api/gateway/stop?streamPath=" + cameraIndexCode + "/" + channel);
//            String code = HttpUtils.sendGet(httpUrl + "/api/gateway/stop?stream=" + cameraIndexCode + "/" + channel);
//            log.info("code---------->" + code);
//            return code;
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return null;
//    }

    /**
     * 车载终端实时流调用的远程天网接口
     *
     * @param camerasVo
     */
    public String apiPreviewURLs(CamerasVo camerasVo) {
        /**
         *  jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006");
         *         jsonBody.put("streamType", 0);
         *         jsonBody.put("protocol","rtsp");
         *         jsonBody.put("transmode", 1);
         *         jsonBody.put("expand","streamform=rtp");
         */
        camerasVo.setProtocol("rtsp");
        camerasVo.setTransmode(1);
        camerasVo.setExpand("streamform=rtp");
        String body = JSONObject.toJSONString(camerasVo);
        String previewURLs = getPreviewURLs("/api/video/v1/cameras/previewURLs", body);
        log.info("-------------------------------->>>>>previewURLs" + previewURLs);
        JSONObject outJson = JSONObject.parse(previewURLs);
        if ("0".equals(outJson.getString("code"))) {
            log.info("outJson----->" + outJson);
            JSONObject data = outJson.getJSONObject("data");
            String urls = data.getString("url");
            return urls;
        } else {
            return "1";
        }
    }

    /**
     * 报警回放本地测试
     * 从天网拉回放流,然后根据url把流下载下来变成文件,然后进行视频压缩
     *
     * @param list
     * @param alarmPlayTimeValue
     */
    public void playbackURLs(List<String> list, String alarmPlayTimeValue) {
        log.info("--------------->playbackURLs");
        CompletableFuture future = CompletableFuture.supplyAsync(() -> {
            log.info("异步任务开始-----》");
//            for (String code : list) {
            String code = "42010001541320000024";
            PlaybackVo playbackVo = new PlaybackVo();
            playbackVo.setCameraIndexCode(code);
            // 获取当前时间
            OffsetDateTime currentTime = OffsetDateTime.now();
            // 获取当前时间的前10分钟时间
            OffsetDateTime beforeTenMinutes = currentTime.minusMinutes(Long.parseLong(alarmPlayTimeValue));
            // 获取当前时间的后10分钟时间
            OffsetDateTime afterTenMinutes = currentTime.plusMinutes(Long.parseLong(alarmPlayTimeValue));
            // 格式化时间
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
            playbackVo.setBeginTime(beforeTenMinutes.format(formatter));
            //现在当前时间:后续需要修改成报警时间的后几分钟
            playbackVo.setEndTime(afterTenMinutes.format(formatter));
            // jsonBody.put("protocol","rtsp");
            //        jsonBody.put("expand","streamform=rtp");
            playbackVo.setProtocol("rtsp");
            playbackVo.setExpand("streamform=rtp");
            //对象转换json字符串
            String body = JSONObject.toJSONString(playbackVo);
            //调用天网接口
            log.info("body----->" + body);
//            String playbackURLs = getPreviewURLs("/api/video/v1/cameras/playbackURLs", body);
//            log.info("playbackURLs----->" + playbackURLs);
//            JSONObject outJson = (JSONObject) JSONObject.parse(playbackURLs);
//            if ("0".equals(outJson.getString("code"))) {
//                log.info("outJson----->" + outJson);
//                JSONObject data = outJson.getJSONObject("data");
//                String urls = data.getString("url");
//                log.info("--------------->urls::" + urls);

            String FilePath = "/opt/streams/map/" + code + ".mp4";
//                String FilePath = "/opt/streams/map/01ea43e6676f4e47bd6c5cd9e02aa006.mp4";
//            try {
//                TimeUnit.SECONDS.sleep(62*Integer.parseInt(alarmPlayTimeValue));
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            Process process = rtspToMP4.StartRecord(ffmpegPath, "rtsp://124.70.58.209:8554/" + code + "/" + code, FilePath);
//            log.info("------playbackURLs----->>>>:" + process);
//            if (null != process) {
//                map.put(code, process);
//            }
//            try {
//                TimeUnit.SECONDS.sleep(70 * Integer.parseInt(alarmPlayTimeValue));
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            log.info("------videoCompression----->>>>:");
//            videoCompression(code);
            return 1;
        });
        future.join();
    }

    public AjaxResult stop(String id) {
        if (map.containsKey(id)) {
            Process process = map.get(id);
            log.info("-----stop------>>>" + process);
            if (null != process) {
                rtspToMP4.stopRecord(process);
                return AjaxResult.success();
            }
        }
        return AjaxResult.error();
    }

    public static void main(String[] args) throws InterruptedException, ParseException, IOException {
//        CameraUtil cameraUtil = new CameraUtil();
//        cameraUtil.closeRecording();
//        String s = "/opt/streams/record/flv/42010001541320001116/20230403_235506_000506-22e1523b-d170-11ed-8a42-fa163e4e1e9f.flv";
//        String fileStr = s.substring(s.lastIndexOf("/") + 1, s.length());
//        String pathStr = s.substring(0, s.lastIndexOf("/"));
//        System.out.println(fileStr);
//        System.out.println(pathStr);

        String s = "20230403235512";
        Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s);
        sdate = DateUtils.addDays(sdate, -1);
        System.out.println(DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, sdate));
    }


    public List<BaseCameraManagementResponse> heartbeatGetPlayFlv() {
        int maxRetries = 5;
        int retryCount = 0;
        boolean success = false;
        JSONArray streamArray = null;
        List<BaseCameraManagementResponse> baseCameraManagementResponseList = new ArrayList<>();
        while (!success && retryCount < maxRetries) {
            try {
                String data = HttpClientUtil.gets(webUrl + "/api/summary");
                log.info("data------------------>" + data);
                if (StringUtils.isNotEmpty(data)) {
                    JSONObject jsonObject = JSONObject.parseObject(data);
                    streamArray = jsonObject.getJSONArray("Streams");
                    success = true;
                }
            } catch (Exception e) {
                log.info("Exception caught: " + e.getMessage());
                // 增加重试计数
                retryCount++;
            }
        }
        for (int i = 0; i < streamArray.size(); i++) {
            BaseCameraManagementResponse baseCameraManagementResponse = new BaseCameraManagementResponse();
            JSONObject subObj = streamArray.getJSONObject(i);
            String subValue = subObj.getString("Subscribers");
            String PathValue = subObj.getString("Path");
            String type = subObj.getString("Type");
            String timestampString = subObj.getString("StartTime");
            ZonedDateTime givenTime = ZonedDateTime.parse(timestampString);
            // 当前时间
            Instant currentTime = Instant.now();
            // 将给定时间转换为Instant对象
            Instant givenInstant = givenTime.toInstant();
            // 计算时间差
            Duration duration = Duration.between(givenInstant, currentTime);
            //封装
            // 获取小时差
            baseCameraManagementResponse.setStartTime(duration.toHours() + "小时前");
            baseCameraManagementResponse.setStreamPath(PathValue);
            baseCameraManagementResponse.setSubscribers(subValue);
            baseCameraManagementResponse.setType(type);
            // 寻找第一个斜杠的位置
            int slashIndex = PathValue.indexOf("/");
            if (slashIndex != -1) {
                BaseCameraManagementResponse response = new BaseCameraManagementResponse();
                String result = PathValue.substring(0, slashIndex);
                BaseCameraManagement cameraManagement = baseCameraManagementService.getOne(new LambdaQueryWrapper<BaseCameraManagement>()
                        .eq(BaseCameraManagement::getCameraCode, result));
                if (!ObjectUtils.isEmpty(cameraManagement)) {
                    baseCameraManagementResponse.setCameraCode(cameraManagement.getCameraCode());
                    baseCameraManagementResponse.setInstallMile(cameraManagement.getInstallMile());
                }
            }
            //取出AudioTracks
            JSONArray audioJson = subObj.getJSONArray("AudioTracks");
            if (audioJson != null && audioJson.size() > 0) {
                for (int v = 0; v < audioJson.size(); v++) {
                    BaseCameraManagementResponse.AudioTracks audioTracks = new BaseCameraManagementResponse.AudioTracks();
                    JSONObject arrayJSONObject = audioJson.getJSONObject(v);
                    String name = arrayJSONObject.getString("Name");
                    String sampleRate = arrayJSONObject.getString("SampleRate");
                    String channels = arrayJSONObject.getString("Channels");
                    String bps = arrayJSONObject.getString("BPS");
                    audioTracks.setBps(bps);
                    audioTracks.setChannels(channels);
                    audioTracks.setName(name);
                    audioTracks.setSampleRate(sampleRate);
                    baseCameraManagementResponse.setAudioTracks(audioTracks);
                }
            }
//            //取出VideoTracks
//            JSONArray videoJson = subObj.getJSONArray("VideoTracks");
//            if (videoJson != null && videoJson.size() > 0) {
//                for (int v = 0; v < videoJson.size(); v++) {
//                    BaseCameraManagementResponse.VideoTracks videoTracks = new BaseCameraManagementResponse.VideoTracks();
//                    JSONObject arrayJSONObject = videoJson.getJSONObject(v);
//                    String name = arrayJSONObject.getString("Name");
//                    String width = arrayJSONObject.getString("Width");
//                    String height = arrayJSONObject.getString("Height");
//                    String resolution = width + "*" + height;
//                    String gop = arrayJSONObject.getString("GOP");
//                    String bps = arrayJSONObject.getString("BPS");
//                    videoTracks.setBps(bps);
//                    videoTracks.setGop(gop);
//                    videoTracks.setName(name);
//                    videoTracks.setResolution(resolution);
//                    baseCameraManagementResponse.setVideoTracks(videoTracks);
//                }
//            }
            baseCameraManagementResponseList.add(baseCameraManagementResponse);
        }

        return baseCameraManagementResponseList;
    }


    /**
     * 根据相机ID找出分组并排序
     *
     * @param baseCameraManagement
     */
    public List<BaseCameraManagement> getBaseCameraManagementList(Long id, Integer line) {
        //根据ID获取当前相机的信息
        BaseCameraManagement baseCameraManagement = baseCameraManagementService.getById(id);
        if (!ObjectUtils.isEmpty(baseCameraManagement)) {
            LambdaQueryWrapper<BaseCameraManagement> wrapper = new LambdaQueryWrapper<>();
            //找出同一分组的相机
            wrapper.eq(BaseCameraManagement::getGrou, baseCameraManagement.getGrou());
            if (line == 1) {
                wrapper.orderByAsc(BaseCameraManagement::getSort);
            } else if (line == 2) {
                wrapper.orderByDesc(BaseCameraManagement::getSort);
            }
            List<BaseCameraManagement> list = baseCameraManagementService.list(wrapper);
            if (!ObjectUtils.isEmpty(list)) {
                return list;
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
    
    
    /**
     * 流媒体的条数
     * @return
     */
    public int urlCount(){
        int maxRetries = 5;
        int retryCount = 0;
        int count = 0;
        boolean success = false;
        JSONArray streamArray = null;
        List<BaseCameraManagementResponse> baseCameraManagementResponseList = new ArrayList<>();
        while (!success && retryCount < maxRetries) {
            try {
                String data = HttpClientUtil.gets(webUrl + "/api/summary");
                log.info("data------------------>" + data);
                if (StringUtils.isNotEmpty(data)) {
                    JSONObject jsonObject = JSONObject.parseObject(data);
                    streamArray = jsonObject.getJSONArray("Streams");
                    success = true;
                }
            } catch (Exception e) {
                log.info("Exception caught: " + e.getMessage());
                // 增加重试计数
                retryCount++;
            }
        }
        for (int i = 0; i < streamArray.size(); i++) {
            JSONObject subObj = streamArray.getJSONObject(i);
            String PathValue = subObj.getString("Path");
            if (PathValue.contains("/h264_720")){
                count++;
            }
        }
        return count;
    }
}
