package com.sooka.sponest.monitor.dahua.service.impl;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.dahuatech.hutool.core.codec.Base64;
import com.dahuatech.hutool.core.io.FileUtil;
import com.dahuatech.hutool.core.io.StreamProgress;
import com.dahuatech.hutool.http.HttpUtil;
import com.dahuatech.hutool.http.Method;
import com.dahuatech.hutool.json.JSONArray;
import com.dahuatech.hutool.json.JSONObject;
import com.dahuatech.hutool.json.JSONUtil;
import com.dahuatech.icc.exception.ClientException;
import com.dahuatech.icc.oauth.http.IccHttpHttpRequest;
import com.dahuatech.icc.oauth.http.IccTokenResponse;
import com.dahuatech.icc.util.BeanUtil;
import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.system.api.domain.SysFile;
import com.sooka.sponest.monitor.base.service.impl.BaseService;
import com.sooka.sponest.monitor.camera.domain.CentermonitorTCamera;
import com.sooka.sponest.monitor.camera.domain.CentermonitorTCameraStateLog;
import com.sooka.sponest.monitor.camera.mapper.CentermonitorTCameraMapper;
import com.sooka.sponest.monitor.camera.service.ICentermonitorTCameraService;
import com.sooka.sponest.monitor.dahua.domain.CenterdataTAttach;
import com.sooka.sponest.monitor.dahua.domain.CentermonitorTMonitoringEquipmentPositionDO;
import com.sooka.sponest.monitor.dahua.domain.PlayBackProperties;
import com.sooka.sponest.monitor.dahua.service.DahuaService;
import com.sooka.sponest.monitor.dahua.utils.HttpEnum;
import com.sooka.sponest.monitor.dahua.utils.HttpTestUtils;
import com.sooka.sponest.monitor.device.mapper.CentermonitorTMonitoringEquipmentPositionMapper;
import com.sooka.sponest.monitor.remoteapi.service.center.data.RemoteDataBaseService;
import com.sooka.sponest.monitor.remoteapi.service.center.event.RemoteEventBaseService;
import com.sooka.sponest.monitor.remoteapi.service.center.event.domain.CentereventTDownloads;
import com.sooka.sponest.monitor.remoteapi.service.center.file.RemoteFileBaseService;
import com.sooka.sponest.monitor.util.Mp4ParserUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.checkerframework.checker.units.qual.A;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

@Service
public class DahuaServiceImpl extends BaseService implements DahuaService {

    private static org.slf4j.Logger log = LoggerFactory.getLogger(DahuaServiceImpl.class);


    @Resource
    private RedisService redisService;

    @Resource
    private ICentermonitorTCameraService iCentermonitorTCameraService;

    @Resource
    private DahuaService dahuaService;

    @Resource
    private RemoteFileBaseService fileBaseService;

    @Resource
    private RemoteDataBaseService dataBaseService;

    @Resource
    private RemoteEventBaseService eventBaseService;

    @Resource
    private CentermonitorTCameraMapper centermonitorTCameraMapper;

    @Resource
    private CentermonitorTMonitoringEquipmentPositionMapper centermonitorTMonitoringEquipmentPositionMapper;

    //按组织获取设备详细信息
    public static final String ACTION = "/videoService/devicesManager/devicesInfo";


    /**
     * 获取大华账号ip等信息
     */
    @Override
    public AjaxResult getDahuaVideoServer() {
        AjaxResult result = new AjaxResult();
        result.put("loginIp", loginIp);
        result.put("loginPort", loginPort);
        return result;

    }

    /**
     * 获取大华账号ip等信息（APP）
     */
    @Override
    public AjaxResult getDahuaVideoServerApp() {
        AjaxResult result = new AjaxResult();
        result.put("loginIpApp", loginIpApp);
        result.put("loginPortApp", loginPortApp);
        return result;
    }

    /**
     * 获取大华ICC服务
     */
    @Override
    public AjaxResult getDahuaDssServer() {
        AjaxResult result = new AjaxResult();
        result.put("host", host);
        result.put("user_name", user_name);
        result.put("password", password);
        result.put("client_id", client_id);
        result.put("client_secret", client_secret);
        result.put("version", version);
        return result;
    }

    /**
     * 获取token
     */
    public String getToken() {
        //如果缓存里有 用缓存的，没有就重新获取
        String token = redisService.getCacheObject("DH_TOKEN");
        if (token != null) {
            return token;
        }
        String TOKEN_URL = host + "/evo-apigw/evo-oauth/" + version + "/oauth/extend/token";
        try {
            log.info("----开始执行----{}------请求地址:{}", "客户端模式_认证申请", TOKEN_URL);
            Map<String, Object> map = new HashMap();
            map.put("grant_type", "client_credentials");
            map.put("client_id", client_id);
            map.put("client_secret", client_secret);
            IccHttpHttpRequest pr = new IccHttpHttpRequest(TOKEN_URL, Method.POST, JSONUtil.toJsonStr(map));
            String prBody = pr.execute();
            IccTokenResponse keyResp = BeanUtil.toBean(prBody, IccTokenResponse.class);
            log.info("----结束执行----{}------返回报文:{}", "客户端模式_认证申请", keyResp);
            token = keyResp.getData().getAccess_token();
            redisService.setCacheObject("DH_TOKEN", token);
            //token 有效期1小时59分
            redisService.expire("DH_TOKEN", 60 * 60 * 2 - 60);
            return token;
        } catch (Exception e) {
            return token;
        }
    }

    /**
     * 获取token
     * 调用此方法以密码形式获取token
     */
    public String getTokenByPassword() {
        //如果缓存里有 用缓存的，没有就重新获取
        String token = redisService.getCacheObject("DH_TOKEN_PASSWORD");
        if (token != null) {
            return token;
        }
        String TOKEN_URL = host + "/evo-apigw/evo-oauth/" + version + "/oauth/extend/token";
        try {
            log.info("----开始执行----{}------请求地址:{}", "客户端模式_认证申请", TOKEN_URL);
            String publicKey = getPublicKey();
            Map<String, Object> map = new HashMap();
            map.put("grant_type", "password");
            map.put("username", userName);
            map.put("password", baseEncrypt(publicKey, password));
            map.put("client_id", client_id);
            map.put("client_secret", client_secret);
            map.put("public_key", publicKey);
            IccHttpHttpRequest pr = new IccHttpHttpRequest(TOKEN_URL, Method.POST, JSONUtil.toJsonStr(map));
            String prBody = pr.execute();
            IccTokenResponse keyResp = BeanUtil.toBean(prBody, IccTokenResponse.class);
            log.info("----结束执行----{}------返回报文:{}", "客户端模式_认证申请", keyResp);
            token = keyResp.getData().getAccess_token();
            redisService.setCacheObject("DH_TOKEN_PASSWORD", token);
            //token 有效期1小时59分
            redisService.expire("DH_TOKEN_PASSWORD", 60 * 60 * 2 - 60);
            return token;
        } catch (Exception e) {
            return token;
        }
    }

    /**
     * 获取公钥
     */
    public String getPublicKey() {
        String PUBLIC_KEY_URL = host + "/evo-apigw/evo-oauth/1.0.0/oauth/public-key";
        try {
            log.info("----开始执行----{}------请求地址:{}", "获取公钥", PUBLIC_KEY_URL);
            IccHttpHttpRequest pr = new IccHttpHttpRequest(PUBLIC_KEY_URL, Method.GET);
            String prBody = pr.execute();
            JSONObject json = JSONUtil.parseObj(prBody);
            if (json.getBool("success")) {
                JSONObject data = JSONUtil.parseObj(json.getObj("data"));
                String publicKey = data.getStr("publicKey");
                log.info("----结束执行----{}------返回报文:{}", "获取公钥", publicKey);
                return publicKey;
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 加密密码
     */
    public String baseEncrypt(String publicKey, String password) {
        try {
            byte[] decoded = com.dahuatech.hutool.core.codec.Base64.decode(publicKey);
            RSAPublicKey pubKey =
                    (RSAPublicKey)
                            KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            // RSA加密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            return Base64.encode(cipher.doFinal(password.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception ex) {
            return ex.getMessage();
        }
    }


    /**
     * 事件订阅
     */
    public AjaxResult eventSubscribe(String name, String monitorUrl, String category, String[] type) throws ClientException {
        String SUBSCRIE_URL = host + "/evo-apigw/evo-event/" + version + "/subscribe/mqinfo";
        String token = getToken();
        log.info("----开始执行----{}------请求地址:{}", "事件订阅", SUBSCRIE_URL);
        Map<String, Object> param = new HashMap();
        List<Map<String, Object>> events = new ArrayList<>();
        events.add(buildEvent(category, type));
        List<Map<String, Object>> monitors = new ArrayList<>();
        Map<String, Object> monitor = new HashMap();
        monitor.put("monitor", monitorUrl);
        monitor.put("monitorType", "url");
        monitor.put("events", events);
        param.put("monitors", monitors);
        Map<String, Object> subsystem = new HashMap();
        subsystem.put("subsystemType", 0);
        subsystem.put("name", StringUtils.isEmpty(name) ? loginIp + "_" + loginPort : name);
        subsystem.put("magic", loginIp + "_" + loginPort);
        monitors.add(monitor);
        param.put("subsystem", subsystem);
        Map<String, Object> requestParam = new HashMap();
        requestParam.put("param", param);
        log.info("----请求参数----{}", JSONUtil.toJsonStr(requestParam));
        IccHttpHttpRequest pr = new IccHttpHttpRequest(SUBSCRIE_URL, Method.POST, JSONUtil.toJsonStr(requestParam));
        pr.getHttpRequest().header("Authorization", "bearer " + token);
        String prBody = pr.execute();
        log.info("----结束执行----{}------返回报文:{}", "事件订阅", prBody);
        JSONObject jsonObject = JSONUtil.parseObj(prBody);
        if ((boolean) jsonObject.get("success")) {
            return AjaxResult.success("订阅成功");
        }
        return AjaxResult.error("订阅失败", jsonObject.get("errMsg").toString());
    }

    /**
     * 事件订阅列表查询
     */
    public AjaxResult subscribeList(String monitorType, String category) throws ClientException {
        if (StringUtils.isEmpty(monitorType) || StringUtils.isEmpty(category)) {
            return AjaxResult.error("必要参数缺失");
        }
        String SUBSCRIE_LIST_URL = host + "/evo-apigw/evo-event/" + version + "/subscribe/subscribe-list";
        String token = getToken();
        log.info("----开始执行----{}------请求地址:{}", "事件订阅列表查询", SUBSCRIE_LIST_URL);
        SUBSCRIE_LIST_URL += "?monitorType=" + monitorType;
        SUBSCRIE_LIST_URL += "&category=" + category;
        log.info("----请求参数----{}", SUBSCRIE_LIST_URL);
        IccHttpHttpRequest pr = new IccHttpHttpRequest(SUBSCRIE_LIST_URL, Method.GET);
        pr.getHttpRequest().header("Authorization", "bearer " + token);
        String prBody = pr.execute();
        log.info("----结束执行----{}------返回报文:{}", "事件订阅列表查询", prBody);
        //这里要用fastJson, huTool序列化 后遇到null值会报错 limeng 20240229
        com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(prBody);
        if (jsonObject.getBoolean("success")) {
            return AjaxResult.success("事件订阅列表查询成功", jsonObject.getString("data"));
        }
        return AjaxResult.error("事件订阅列表查询失败", jsonObject.getString("errMsg"));
    }

    /**
     * 取消事件订阅
     */
    public AjaxResult removeEventSubscribe(String name) throws ClientException {
        String SUBSCRIE_URL = host + "/evo-apigw/evo-event/" + version + "/subscribe/mqinfo";
        if (StringUtils.isEmpty(name)) {
            return AjaxResult.error("必要参数缺失");
        }
        String token = getToken();
        log.info("----开始执行----{}------请求地址:{}", "取消事件订阅", SUBSCRIE_URL);
        SUBSCRIE_URL += "?name=" + name;
        log.info("----请求参数----{}", SUBSCRIE_URL);
        IccHttpHttpRequest pr = new IccHttpHttpRequest(SUBSCRIE_URL, Method.DELETE);
        pr.getHttpRequest().header("Authorization", "bearer " + token);
        String prBody = pr.execute();
        log.info("----结束执行----{}------返回报文:{}", "取消事件订阅", prBody);
        JSONObject jsonObject = JSONUtil.parseObj(prBody);
        if ((boolean) jsonObject.get("success")) {
            return AjaxResult.success("取消事件订阅成功", jsonObject);
        }
        return AjaxResult.error("取消事件订阅失败", jsonObject.get("errMsg").toString());
    }

    /**
     * 火点联动
     *
     * @Param lng
     * @Param lat
     * @Param list 摄像头唯一标识 list
     */
    public AjaxResult rotation(Double lng, Double lat, List<String> list) {
        String prBody = null;
        String ROTATION_URL = host + "/evo-apigw/evo-gmcommon/" + version + "/watchtower/rotation/to/specify/fire/point";
        String token = getToken();
        Map<String, Object> param = new HashMap();
        //火点坐标
        param.put("lng", lng);
        param.put("lat", lat);
        //需要联动的摄像头唯一标识List
        param.put("channelSns", list);
        log.info("----开始执行----{}------请求参数:{}", "火点联动", JSONUtil.toJsonStr(param));
        try {
            IccHttpHttpRequest pr = new IccHttpHttpRequest(ROTATION_URL, Method.POST, JSONUtil.toJsonStr(param));
            pr.getHttpRequest().header("Authorization", "bearer " + token);
            prBody = pr.execute();
            log.info("----结束执行----{}------返回报文:{}", "火点联动", prBody);
            return AjaxResult.success("操作成功");
        } catch (Exception ex) {
            ex.printStackTrace();
            JSONObject jsonObject = JSONUtil.parseObj(prBody);
            return AjaxResult.error("操作失败", jsonObject.get("errMsg").toString());
        }
    }

    /**
     * 同步摄像头离线状态
     * 调用此方法以将大华平台摄像头状态同步到一体化平台监控中心
     */
    public AjaxResult synchronizeOfflineCamera() {
        try {
            JSONArray jsonArray = this.startPage(1);
            this.syncWorkingStatus(jsonArray);
            return AjaxResult.success();
        } catch (Exception ex) {
            ex.printStackTrace();
            return AjaxResult.error("操作失败");
        }
    }

    /**
     * 获取大华摄像头的预置点
     */
    public AjaxResult getPresetPoints(String channelId) {
        String prBody = null;
        String GET_PRESET_POINTS_URL = host + "/evo-apigw/admin/API/DMS/Ptz/GetPresetPoints";
        String token = getTokenByPassword();
        Map<String, Object> param = new HashMap<>();
        Map<String, Object> data = new HashMap<>();
        data.put("channelId", channelId);
        param.put("data", data);
        log.info("----开始执行----{}------请求参数:{}", "获取大华摄像头的预置点", JSONUtil.toJsonStr(param));
        try {
            IccHttpHttpRequest pr = new IccHttpHttpRequest(GET_PRESET_POINTS_URL, Method.POST, JSONUtil.toJsonStr(param));
            pr.getHttpRequest().header("Authorization", "bearer " + token);
            prBody = pr.execute();
            log.info("----结束执行----{}------返回报文:{}", "获取大华摄像头的预置点", prBody);
            return AjaxResult.success("操作成功", JSONUtil.parseObj(prBody));
        } catch (Exception ex) {
            ex.printStackTrace();
            JSONObject jsonObject = JSONUtil.parseObj(prBody);
            return AjaxResult.error("操作失败", jsonObject.get("errMsg").toString());
        }
    }

    /**
     * 预置点控制(添加/删除/定位)
     */
    public AjaxResult operatePresetPoint(String channelId, String presetPointCode, String presetPointName, String operateType) {
        String prBody = "";
        String OPERATE_PRESET_POINTS_URL = host + "/evo-apigw/admin/API/DMS/Ptz/OperatePresetPoint";
        String token = getTokenByPassword();
        Map<String, Object> param = new HashMap<>();
        Map<String, Object> data = new HashMap<>();
        data.put("channelId", channelId);
        data.put("presetPointCode", presetPointCode);
        data.put("presetPointName", presetPointName);
        data.put("operateType", operateType);
        param.put("data", data);
        log.info("----开始执行----{}------请求参数:{}", "预置点控制(添加/删除/定位)", JSONUtil.toJsonStr(param));
        try {
            IccHttpHttpRequest pr = new IccHttpHttpRequest(OPERATE_PRESET_POINTS_URL, Method.POST, JSONUtil.toJsonStr(param));
            pr.getHttpRequest()
                    .header("Authorization", "bearer " + token)
                    .header("User-Id", "1");
            prBody = pr.execute();
            log.info("----结束执行----{}------返回报文:{}", "预置点控制(添加/删除/定位)", prBody);
            return AjaxResult.success("操作成功", JSONUtils.parse(prBody));
        } catch (Exception ex) {
            ex.printStackTrace();
            return AjaxResult.error("操作失败", JSONUtils.parse(prBody));
        }
    }

    public JSONArray startPage(Integer _pageNum) {
        JSONArray result = new JSONArray();
        String response = this.getOfflineCamera(_pageNum);
        JSONObject jsonObject = JSONUtil.parseObj(response);
        if (jsonObject.getInt("code") == 0 && jsonObject.getBool("success")) {
            Integer currentPage = jsonObject.getJSONObject("data").getInt("currentPage");
            Integer totalPage = jsonObject.getJSONObject("data").getInt("totalPage");
            log.info("----执行----{}----totalPage----{}------currentPage----{}------", "同步摄像头离线状态", totalPage, currentPage);
            if (totalPage > currentPage) {
                /** 如果有多页，先将第一页的数据存入集合，再请求其他页 **/
                result.addAll(jsonObject.getJSONObject("data").getJSONArray("pageData"));
                while (totalPage > currentPage) {
                    currentPage += 1;
                    String res = this.getOfflineCamera(currentPage);
                    log.info("----执行----{}----totalPage----{}------currentPage----{}------", "同步摄像头离线状态", totalPage, currentPage);
                    JSONObject response_json = JSONUtil.parseObj(res);
                    result.addAll(response_json.getJSONObject("data").getJSONArray("pageData"));
                }
            } else {
                result.addAll(jsonObject.getJSONObject("data").getJSONArray("pageData"));
            }
        }
        return result;
    }

    public String getOfflineCamera(Integer _pageNum) {
        String prBody = null;
        String PAGE_URL = host + "/evo-apigw/evo-brm/" + version + "/device/subsystem/page";
        Integer pageNum = _pageNum;
        String pageSize = "1000";
        String[] ownerCodes = {"001"};
        String token = getToken();
        Map<String, Object> param = new HashMap();
        //请求参数
        param.put("pageNum", pageNum);
        param.put("pageSize", pageSize);
        /** 设备所属组织编码集合 **/
        param.put("ownerCodes", ownerCodes);
        /** 是否获取设备所属组织子节点下设备记录 **/
        param.put("showChildNodeData", 1);
        /** 0:离线 1:在线 **/
        param.put("isOnline", 0);
        /** 0:获取非虚拟设备 1 只获取虚拟设备 **/
        param.put("syncVirtualData", 0);
        log.info("----开始执行----{}------请求参数:{}", "同步摄像头离线状态", JSONUtil.toJsonStr(param));
        try {
            IccHttpHttpRequest pr = new IccHttpHttpRequest(PAGE_URL, Method.POST, JSONUtil.toJsonStr(param));
            pr.getHttpRequest().header("Authorization", "bearer " + token);
            prBody = pr.execute();
            log.info("----结束执行----{}------返回报文:{}", "同步摄像头离线状态", prBody);
            return prBody;
        } catch (Exception ex) {
            ex.printStackTrace();
            return prBody;
        }
    }

    public void syncWorkingStatus(JSONArray jsonArray) {
        if (jsonArray.size() > 0) {
            //先把所有摄像头改成在线，然后再把查询回来的摄像头改成离线，防止接收不到上线通知而导致无法正常上线
            CentermonitorTCamera updAll = new CentermonitorTCamera();
            updAll.setOfflineReason("0");
            updAll.setWorkingStatus("0");
            centermonitorTCameraMapper.updateCameraWorkingStatus(updAll);
            for (int i = 0; i < jsonArray.size(); i++) {
                String deviceCode = jsonArray.getJSONObject(i).getStr("deviceCode");
                String offlineReason = jsonArray.getJSONObject(i).getStr("offlineReason");
                CentermonitorTCamera camera = iCentermonitorTCameraService.getCameraByChannelNum(deviceCode);
                if (camera != null) {
                    //摄像头状态修改对象
                    camera.setOfflineReason(offlineReason);
                    camera.setWorkingStatus("1");//0上线 1下线 225低电压
                    //日志插入对象
                    CentermonitorTCameraStateLog stateLog = new CentermonitorTCameraStateLog();
                    stateLog.setCameraId(camera.getId());
                    stateLog.setCreateTime(DateUtils.getTime());
                    stateLog.setState(offlineReason);
                    stateLog.setReportText(jsonArray.getJSONObject(i).toString());
                    //更改状态并加入日志
                    iCentermonitorTCameraService.updateCameraWorkingStatus(camera, stateLog);
                } else {
                    log.info("未查询到摄像头，deviceCode----{}", deviceCode);
                }
            }
        }
//        try {
//            getLongPollingPositionMsg();
//        } catch (Exception e) {
//            log.info("未查询到执法记录仪");
//        }
    }


    /**
     * 获取记录仪位置数据
     */
    @Override
    public void insertEquipmentPosition(CentermonitorTMonitoringEquipmentPositionDO centermonitorTMonitoringEquipmentPositionDO) {
        centermonitorTMonitoringEquipmentPositionMapper.insertEquipmentPosition(centermonitorTMonitoringEquipmentPositionDO);
    }


    /**
     * 获取执法记录仪token
     */
    public void getLongPollingPositionMsg() throws Exception {
        R<?> result = HttpTestUtils.getToken(loginIp, loginPort, userName, userPwd);
        if (result.getCode() != 200) {
            log.info("获取token失败，请检查配置信息:", com.alibaba.fastjson.JSONObject.parseObject(result.getMsg()));
        }
        String token = result.getData().toString();
        getMessage(loginIp, loginPort, token);
    }

    /**
     * 根据组织code编码获取执法仪详情数据
     *
     * @param ip
     * @param port
     * @param token
     */
    private void getMessage(String ip, int port, String token) {
        Map<String, String> content = new HashMap<>();
        content.put("orgCode", "9370184169490624");
        String response = HttpTestUtils.httpRequest(HttpEnum.POST, ip, port, ACTION, token, new Gson().toJson(content));
        Map<String, Object> rsp = new Gson().fromJson(response, Map.class);
        List<Map<String, Object>> arr = (List<Map<String, Object>>) rsp.get("devices");
        extracted(arr);
    }

    /**
     * 更新执法仪在离线状态
     *
     * @param arr
     */
    private void extracted(List<Map<String, Object>> arr) {
        if (CollectionUtils.isNotEmpty(arr)) {
            for (Map<String, Object> item : arr) {
                centermonitorTCameraMapper.updateLawEnforcementInstrumentState(item.get("status").toString().equals("0") ? "1" : "0", item.get("code").toString());
            }
        }
    }

    public AjaxResult getPlaybackByTime(String properties) {
        log.info("**GetPlaybackByTime->"+new Date()+"->start**");
        List<PlayBackProperties> propertiesList = JSON.parseArray(properties, PlayBackProperties.class);
        for (PlayBackProperties property: propertiesList) {
            //下载并上传视频
            AjaxResult ajaxResult = getPlaybackByTime(property);
            //将视频下载结果保存至事件中心
            CentereventTDownloads downloads = new CentereventTDownloads();
            downloads.setId(property.getId());
            if (Integer.parseInt(ajaxResult.get("code").toString()) == HttpStatus.SUCCESS) {
                downloads.setPath(ajaxResult.get("data").toString());
            }
            downloads.setFlag(ajaxResult.get("code").toString());
            downloads.setReason(ajaxResult.get("msg").toString());
            eventBaseService.downloads(downloads);
        }
        log.info("**GetPlaybackByTime->"+new Date()+"->end**");
        return AjaxResult.success();
    }

    public AjaxResult getPlaybackByTime(PlayBackProperties playBackProperties) {
        AjaxResult ajaxResult = new AjaxResult();
        CentermonitorTCamera camera = iCentermonitorTCameraService.selectCentermonitorTCameraById(playBackProperties.getCameraId());
        if (camera == null) {
            return new AjaxResult(HttpStatus.ACCEPTED, "未查询到该摄像头");
        } else if (camera.getChannelNum().isEmpty()) {
            return new AjaxResult(HttpStatus.ACCEPTED, "未查询到该摄像头通道编号");
        }
        //开始时间
        Long startTimeStamp = dahuaService.getTimeSeconds(playBackProperties.getStartTime());
        //结束时间
        Long endTimeStamp = dahuaService.getTimeSeconds(playBackProperties.getEndTime());
        //录像请求地址
        String QUERY_RECORDS_URL = host + "/evo-apigw/admin/API/SS/Record/QueryRecords";
        //获取大华token
        String token = dahuaService.getToken();
        //构造请求参数
        Map<String, Object> param = new HashMap<>();
        Map<String, Object> data = new HashMap<>();
        data.put("channelId", camera.getChannelNum());
        data.put("recordSource", "3");
        data.put("startTime", startTimeStamp);
        data.put("endTime", endTimeStamp);
        data.put("recordType", "0");
        data.put("streamType", "1");
        param.put("data", data);
        //请求大华服务器查询录像
        log.info("getPlaybackByTime-查询大华录像、");
        JSONObject QueryRecordsResult = dahuaService.IccHttpHttpRequest(QUERY_RECORDS_URL, Method.POST, JSONUtil.toJsonStr(param), token, "QueryRecords");
        //处理返回值
        if (QueryRecordsResult.get("code") != null && QueryRecordsResult.get("code").toString().equals("1000")) {
            //未查询到录像
            if (QueryRecordsResult.getJSONObject("data") != null && QueryRecordsResult.getJSONObject("data").getJSONArray("records").isEmpty()) {
                log.info("getPlaybackByTime-查询大华录像-result => {}", "该时段未查询到录像信息");
                return new AjaxResult(HttpStatus.ACCEPTED, "该时段未查询到录像信息");
                //查询到路线
            } else {
                List<String> fileNames = new ArrayList<>();
                String dssFileDownloadUrl = dahuaService.isWindows() ? videoDownloadUrlWin : videoDownloadUrlLinux;
                JSONArray records = QueryRecordsResult.getJSONObject("data").getJSONArray("records");
                for (Object record : records) {
                    JSONObject jsonObject = JSONUtil.parseObj(record);
                    String url = host + "/download/vod/cam/download.mp4";
                    url += "?vcuid=" + camera.getChannelNum().split("\\$")[0] + "%240";
                    url += "&subtype=1";
                    url += "&starttime=" + dahuaService.secondsToFormat(Long.parseLong(jsonObject.getStr("startTime")));
                    url += "&endtime=" + dahuaService.secondsToFormat(Long.parseLong(jsonObject.getStr("endTime")));
                    url += "&videoType=3";//videoType 2：设备录像 3：平台录像
                    url += "&substream=1";//substream 码流类型：1：主码流；2：辅码流
                    url += "&token=1:" + token;
                    url += "&recordType=1";
                    String fileName = dssFileDownloadUrl + System.currentTimeMillis() + ".mp4";
                    //下载 录像
                    HttpUtil.downloadFile(url, FileUtil.file(fileName), new StreamProgress() {
                        @Override
                        public void start() {
                            log.info("getPlaybackByTime logId={} => 开始下载", playBackProperties.getLogId());
                        }

                        @Override
                        public void progress(long progressSize) {
//                        log.info("getPlaybackByTime => 已下载：{}", FileUtil.readableFileSize(progressSize));
                        }

                        @Override
                        public void finish() {
                            log.info("getPlaybackByTime logId={} => 下载完成！", playBackProperties.getLogId());
                            fileNames.add(fileName);

                        }
                    });
                }
                File file;
                //如果有多个视频 则合并视频并上传合并后的视频
                if (fileNames.size() > 1) {
                    //合并本地下载的视频
                    String fileName = dssFileDownloadUrl + System.currentTimeMillis() + ".mp4";
                    file = new File(fileName);
                    Mp4ParserUtils.mergeVideo(fileNames, file);
                } else {
                    file = new File(fileNames.get(0));
                }
                //文件上传到文件服务器
                R<SysFile> sysFileR = fileBaseService.upload(Mp4ParserUtils.getMultipartFile(file));
                if (sysFileR.getCode() == 200) {
                    log.info("getPlaybackByTime => 文件上传成功！{}", sysFileR.getData().getUrl());
                    //保存到数据中心
                    CenterdataTAttach attach = new CenterdataTAttach();
                    attach.setBusId(playBackProperties.getLogId());
                    attach.setAttachPath(sysFileR.getData().getUrl());
                    attach.setFileName(sysFileR.getData().getName());
                    attach.setBusSource("PC");
                    attach.setFileType("video");
                    dataBaseService.insertAttach(attach);
                    //清空文件夹
                    File folder = new File(dssFileDownloadUrl);
                    File[] files = folder.listFiles();
                    if (files != null){
                        for (File f : files) {
                            boolean b = f.delete();
                            if(!b) log.error("getPlaybackByTime => 文件删除失败！");
                        }
                    }
                } else {
                    log.info("getPlaybackByTime => 文件上传失败！{}", sysFileR.getMsg());
                }
                return AjaxResult.success("文件下载成功", sysFileR.getData().getUrl());
            }
        }else {
            log.error("getPlaybackByTime-查询大华录像-{}, result => {}", "录像回放接口报错", JSONUtil.toJsonStr(QueryRecordsResult));
            return AjaxResult.error("录像回放接口报错", QueryRecordsResult.getStr("desc"));
        }
    }



    public JSONObject IccHttpHttpRequest(String url, Method method, String param, String token, String action) {
        log.info("----开始执行----{}------请求参数:{}", action, JSONUtil.toJsonStr(param));
        String prBody;
        IccHttpHttpRequest pr;
        try {
            pr = new IccHttpHttpRequest(url, method, param);
        } catch (ClientException e) {
            throw new RuntimeException(e);
        }
        pr.getHttpRequest().header("Authorization", "bearer " + token).header("User-Id", "1");
        prBody = pr.execute();
        log.info("----结束执行----{}------返回报文:{}", action, prBody);
        JSONObject result = JSONUtil.parseObj(prBody);
        return result;
    }

    /**
     * 远程获取图片路径
     *
     * @param attach_ids
     */
    @Override
    public List<CenterdataTAttach> getImgUrl(List<CenterdataTAttach> attach_ids) {
        String token = this.getToken();
        for (int i = 0; i < attach_ids.size(); i++) {
            attach_ids.get(i).setAttachPath(host + "/evo-apigw/evo-oss/" + attach_ids.get(i).getAttachPath() + "?token=" + token);
        }
        return attach_ids;
    }

    /**
     * 构建event对象
     */
    private Map<String, Object> buildEvent(String category, String[] types) {
        Map<String, Object> event = new HashMap();
        event.put("category", category);
        event.put("subscribeAll", 1);
        event.put("domainSubscribe", 2);
        List<Map<String, Object>> authorities = new ArrayList<>();
        Map<String, Object> auth = new HashMap();
        auth.put("types", types);
        authorities.add(auth);
        event.put("authorities", authorities);
        return event;
    }


    public Long getTimeSeconds(String time) {

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long timeStamp = 0;
        try {
            Date date = simpleDateFormat.parse(time);
            timeStamp = date.getTime() / 1000L;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return timeStamp;
    }

    public String secondsToFormat(Long seconds) {
        Date d = new Date();
        d.setTime(seconds * 1000);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_M_d_HH_mm_ss");
        return simpleDateFormat.format(d);
    }


    /**
     * 判断操作系统是否是 Windows
     *
     * @return true：操作系统是 Windows
     * false：其它操作系统
     */
    public boolean isWindows() {
        String osName = getOsName();
        return osName != null && osName.startsWith("Windows");
    }

    /**
     * 获取操作系统名称
     *
     * @return os.name 属性值
     */
    public static String getOsName() {
        return System.getProperty("os.name");
    }


}
