package com.yfd.monitor.gdw2019.transmit.cmd.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import com.yfd.monitor.common.StreamInfo;
import com.yfd.monitor.conf.UserSetting;
import com.yfd.monitor.conf.exception.ControllerException;
import com.yfd.monitor.gdw2019.bean.*;
import com.yfd.monitor.gdw2019.event.SipSubscribe;
import com.yfd.monitor.gdw2019.transmit.SIPSender;
import com.yfd.monitor.gdw2019.transmit.callback.DeferredResultHolder;
import com.yfd.monitor.gdw2019.transmit.callback.RequestMessage;
import com.yfd.monitor.gdw2019.transmit.cmd.ISIPCommanderForPlatform;
import com.yfd.monitor.gdw2019.transmit.cmd.SIPRequestHeaderPlarformProvider;
import com.yfd.monitor.gdw2019.utils.SipUtils;
import com.yfd.monitor.gdw2019.utils.VideoToImageUtil;
import com.yfd.monitor.media.zlm.ZLMRTPServerFactory;
import com.yfd.monitor.media.zlm.dto.MediaServerItem;
import com.yfd.monitor.service.IMediaServerService;
import com.yfd.monitor.service.IPlayService;
import com.yfd.monitor.storager.IRedisCatchStorage;
import com.yfd.monitor.storager.IVideoManagerStorage;
import com.yfd.monitor.storager.dao.DeviceChannelMapper;
import com.yfd.monitor.storager.dao.dto.PlatformRegisterInfo;
import com.yfd.monitor.utils.DateUtil;
import com.yfd.monitor.utils.HttpUtils;
import com.yfd.monitor.vmanager.bean.ErrorCode;
import com.yfd.monitor.vmanager.bean.StreamContent;
import com.yfd.monitor.vmanager.bean.WVPResult;
import gov.nist.javax.sip.message.MessageFactoryImpl;
import gov.nist.javax.sip.message.SIPRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.async.DeferredResult;

import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.header.CallIdHeader;
import javax.sip.header.WWWAuthenticateHeader;
import javax.sip.message.Request;
import java.io.File;
import java.io.FileInputStream;
import java.security.MessageDigest;
import java.text.ParseException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Component
@DependsOn("sipLayer")
public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {

    private final Logger logger = LoggerFactory.getLogger(SIPCommanderFroPlatform.class);

    private int count = 0;
    @Autowired
    private SIPRequestHeaderPlarformProvider headerProviderPlatformProvider;

    @Autowired
    private IRedisCatchStorage redisCatchStorage;

    @Autowired
    private IVideoManagerStorage storager;

    @Autowired
    private IMediaServerService mediaServerService;

    @Autowired
    private SipSubscribe sipSubscribe;

    @Autowired
    private ZLMRTPServerFactory zlmServerFactory;

    @Autowired
    private SIPSender sipSender;

    @Autowired
    private DeviceChannelMapper channelMapper;

    @Autowired
    private UserSetting userSetting;

    @Autowired
    private DeferredResultHolder resultHolder;

    @Autowired
    private SIPCommander cmder;


    @Autowired
    private DeviceChannelMapper deviceChannelMapper;

    @Override
    public void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
        register(parentPlatform, null, null, errorEvent, okEvent, true);
    }

    @Override
    public void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo,
                         SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException,
            ParseException, SipException {

        register(parentPlatform, sipTransactionInfo, null, errorEvent, okEvent, true);
    }

    @Override
    public void unregister(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
        register(parentPlatform, sipTransactionInfo, null, errorEvent, okEvent, false);
    }

    @Override
    public void register(ParentPlatform parentPlatform, @Nullable SipTransactionInfo sipTransactionInfo, @Nullable WWWAuthenticateHeader www,
                         SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent, boolean isRegister) throws SipException, InvalidArgumentException, ParseException {
        Request request;

        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(), parentPlatform.getTransport());
        if ("22.58.167.120".equals(parentPlatform.getDeviceIp())) {
            logger.info("B接口发送信息" + callIdHeader);
        }
        String fromTag = SipUtils.getNewFromTag();
        String toTag = null;
        if (sipTransactionInfo != null) {
            if (sipTransactionInfo.getCallId() != null) {
                callIdHeader.setCallId(sipTransactionInfo.getCallId());
            }
            if (sipTransactionInfo.getFromTag() != null) {
                fromTag = sipTransactionInfo.getFromTag();
            }
            if (sipTransactionInfo.getToTag() != null) {
                toTag = sipTransactionInfo.getToTag();
            }
        }
        String callIdFromHeader = callIdHeader.getCallId();
        redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, PlatformRegisterInfo.getInstance(parentPlatform.getServerGBId(), isRegister));
        if (www == null) {
            request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform,
                    redisCatchStorage.getCSEQ(), fromTag,
                    toTag, callIdHeader, isRegister ? parentPlatform.getExpires() : 0);
            // 将 callid 写入缓存， 等注册成功可以更新状态


            sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (event) -> {
                if (event != null) {
                    logger.info("向上级平台 [ {} ] 注册发生错误： {} ",
                            parentPlatform.getServerGBId(),
                            event.msg);
                }
                redisCatchStorage.delPlatformRegisterInfo(callIdFromHeader);
                if (errorEvent != null) {
                    errorEvent.response(event);
                }
            });

        } else {
            request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform, fromTag, toTag, www, callIdHeader, isRegister ? parentPlatform.getExpires() : 0);
        }

        sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, null, okEvent);
    }

    @Override
    public void sendCatalogNotice(ParentPlatform parentPlatform, @Nullable SipTransactionInfo sipTransactionInfo) throws InvalidArgumentException, ParseException, SipException {
        if (parentPlatform == null) {
            return;
        }
        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(), parentPlatform.getTransport());
        String fromTag = SipUtils.getNewFromTag();
        String toTag = null;
        if (sipTransactionInfo != null) {
            if (sipTransactionInfo.getCallId() != null) {
                callIdHeader.setCallId(sipTransactionInfo.getCallId());
            }
            if (sipTransactionInfo.getFromTag() != null) {
                fromTag = sipTransactionInfo.getFromTag();
            }
            if (sipTransactionInfo.getToTag() != null) {
                toTag = sipTransactionInfo.getToTag();
            }
        }

        // 准备回复通道信息
        List<DeviceChannel> channels = storager.queryChannelWithPlatform(parentPlatform.getServerGBId());
//        List<DeviceChannel> deviceChannels = channels.subList(0, 4);

//        // 将列表拆分成每次最多10条的子列表
        List<List<DeviceChannel>> chunkedList = IntStream.range(0, (channels.size() + 3) / 4)
                .mapToObj(i -> channels.stream()
                        .skip(i * 4)
                        .limit(4)
                        .collect(Collectors.toList()))
                .collect(Collectors.toList());

        // 逐个发送数据
        for (List<DeviceChannel> deviceChannels : chunkedList) {
            StringBuffer catalogXml = new StringBuffer();

            catalogXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n")
                    .append("<SIP_XML EventType=\"Push_Resource\">\r\n")
                    .append("<Code>" + parentPlatform.getCatalogId() + "</Code>\r\n")
                    .append("<SubList  SubNum=\"" + deviceChannels.size() + "\">\r\n");

            if (deviceChannels.size() > 0) {
                for (DeviceChannel channel : deviceChannels) {
                    catalogXml.append("<Item Code=\"" + channel.getDeviceId() + "\" ");
                    catalogXml.append("Name=\"" + channel.getName() + "\" ");
                    catalogXml.append("Status=\"" + channel.getStatus() + "\" ");
                    catalogXml.append("DecoderTag=\"108\" ");
                    catalogXml.append("Longitude=\"" + 0 + "\" ");
                    catalogXml.append("Latitude=\"" + 0 + "\" ");
                    catalogXml.append("SubNum=\"" + 0 + "\"/>\r\n ");
                }
            }
            catalogXml.append("</SubList>\r\n");
            catalogXml.append("</SIP_XML>\r\n");
            Request request = headerProviderPlatformProvider.createNoticeRequest2(parentPlatform, catalogXml.toString(), fromTag, SipUtils.getNewViaTag(), toTag, callIdHeader);
            sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);
//            break;
        }

    }

    /**
     * 向上级回复通道信息
     *
     * @param Code      查询目录编码
     * @param FromIndex 节点下记录
     * @param ToIndex   节点下记录
     */
    @Override
    public String queryCatalog(ParentPlatform parentPlatform, String Code, String FromIndex, String ToIndex, String fromTag) {
        // 准备回复通道信息
//        List<DeviceChannel> channels = storager.queryChannelWithCatalog(Code);
//        int index = NumberUtil.parseInt(FromIndex);
//        int fromIndex = NumberUtil.parseInt(ToIndex);
//        List<DeviceChannel> subList = channels.subList(index - 1, Math.min(channels.size(), fromIndex));
//        StringBuffer catalogXml = new StringBuffer();
//        catalogXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n")
//                .append("<SIP_XML EventType=\"Response_Resource\">\r\n")
//                .append("<SubList Code=\"" + Code + "\" RealNum=\"" + channels.size() + "\" SubNum=\"" + subList.size() + "\"" +
//                        " FromIndex=\"" + FromIndex + "\" ToIndex=\"" + ToIndex + "\">\r\n");
//        if (subList.size() > 0) {
//            int x = 0;
//            for (DeviceChannel channel : subList) {
//
//                x++;
//                catalogXml.append("<Item Code=\"" + channel.getDeviceId() + "\" ");
//                catalogXml.append("Name=\"" + channel.getName() + "\" ");
//                catalogXml.append("Status=\"" + channel.getStatus() + "\" ");
//                catalogXml.append("DecoderTag=\"100\" ");
//                catalogXml.append("Longitude=\"" + channel.getLongitude() + "\" ");
//                catalogXml.append("Latitude=\"" + channel.getLatitude() + "\" ");
//                catalogXml.append("SubNum=\"" + 0 + "\"/>\r\n ");
//            }
//        }
//        catalogXml.append("</SubList>\r\n");
//        catalogXml.append("</SIP_XML>\r\n");
//        return catalogXml.toString();

        // 准备回复通道信息
        List<DeviceChannel> channels = storager.queryChannelWithCatalog(Code);
        int index = NumberUtil.parseInt(FromIndex);
        int fromIndex = NumberUtil.parseInt(FromIndex);
        List<DeviceChannel> subList = channels.subList(index-1, Math.min(channels.size(), fromIndex));
        StringBuffer catalogXml = new StringBuffer();
        catalogXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n")
                .append("<SIP_XML EventType=\"Response_Resource\">\r\n")
                .append("<SubList Code=\"" + Code + "\" RealNum=\"" + channels.size() + "\" SubNum=\"" + subList.size() + "\"" +
                        " FromIndex=\"" + FromIndex + "\" ToIndex=\"" + ToIndex + "\">\r\n");
        if (subList.size() > 0) {
            for (DeviceChannel channel : subList) {
                catalogXml.append("<Item Code=\"" + channel.getDeviceId() + "\" ");
                catalogXml.append("Name=\"" + channel.getName() + "\" ");
                catalogXml.append("Status=\"" + channel.getStatus() + "\" ");
                catalogXml.append("DecoderTag=\"108\" ");
                catalogXml.append("Longitude=\"" + 0 + "\" ");
                catalogXml.append("Latitude=\"" + 0 + "\" ");
                catalogXml.append("SubNum=\"" + 0 + "\"/>\r\n ");
            }
        }
        catalogXml.append("</SubList>\r\n");
        catalogXml.append("</SIP_XML>\r\n");
        return catalogXml.toString();
    }

    /**
     * 查询设备历史报警信息
     *
     * @param Code      查询告警地址编码，视频通道
     * @param UserCode  用户地址编码
     * @param Type      告警类型，见订阅行为
     * @param BeginTime 开始时间，格式如 1990-01-01T00:00:00Z
     * @param EndTime   结束时间，格式如 1990-01-01T00:00:00Z
     * @param Level     告警级别，仅当节点为告警且全网有统一的告
     *                  警级别规划时有效，0 表示未定义告警级别
     * @param FromIndex
     * @param ToIndex
     * @return
     */
    @Override
    public String queryHistoryAlarm(ParentPlatform parentPlatform, String Code, String UserCode, String Type,
                                    String BeginTime, String EndTime, String Level, String FromIndex, String ToIndex) {
        int index = NumberUtil.parseInt(FromIndex);
        int size = (NumberUtil.parseInt(FromIndex) - index) + 1;
        List<Map<String, Object>> alarms = storager.queryHistoryAlarmlog(Code, UserCode, Type, BeginTime, EndTime,
                Level, index, size);
        StringBuilder catalogXml = new StringBuilder();
        catalogXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n")
                .append("<SIP_XML EventType=\"Response_History_Alarm\">\r\n").append("<SubList  RealNum=\"").append(alarms.size()).append("\" SubNum=\"").append(alarms.size()).append("\"").append(" FromIndex=\"").append(FromIndex).append("\" ToIndex=\"").append(ToIndex).append("\">\r\n");
        if (alarms.size() > 0) {
            for (Map<String, Object> deviceAlarm : alarms) {
                catalogXml.append("<Item Code=\"").append(deviceAlarm.get("channelId")).append("\" ");
                catalogXml.append("BeginTime=\"").append(deviceAlarm.get("alarmTime")).append("\" ");
                catalogXml.append("Status=\"").append(deviceAlarm.get("status")).append("\" ");
                catalogXml.append("Type=\"").append(deviceAlarm.get("alarmType")).append("\"/>\r\n ");
            }
        }
        catalogXml.append("</SubList>\r\n");
        catalogXml.append("</SIP_XML>\r\n");
        return catalogXml.toString();
    }

    /**
     * 查询设备录像检索
     *
     * @param Code      查询告警地址编码，视频通道
     * @param UserCode  用户地址编码
     * @param Type      告警类型，见订阅行为
     * @param beginTime 开始时间，格式如 1990-01-01T00:00:00Z
     * @param endTime   结束时间，格式如 1990-01-01T00:00:00Z
     *                  警级别规划时有效，0 表示未定义告警级别
     * @param FromIndex
     * @param ToIndex
     * @return
     */
    @Override
    public String queryDeviceRecord(ParentPlatform parentPlatform, String Code, String UserCode, String Type,
                                    String beginTime, String endTime, String FromIndex, String ToIndex) {

        if (logger.isDebugEnabled()) {
            logger.debug(String.format("录像信息查询 API调用，deviceId：%s ，startTime：%s， endTime：%s", Code, beginTime,
                    endTime));
        }
        DeferredResult<WVPResult<RecordInfo>> result = new DeferredResult<>();
        if (!DateUtil.verification(beginTime, DateUtil.formatter)) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime格式为" + DateUtil.PATTERN);
        }
        if (!DateUtil.verification(endTime, DateUtil.formatter)) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "endTime格式为" + DateUtil.PATTERN);
        }
        List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannelByChannelId(Code);
        if (deviceChannels.size() <= 0) {
            return null;
        }
        DeviceChannel deviceChannel = deviceChannels.get(0);
        //根据摄像头id,查询出对应Nvr设备
        Device device = storager.queryNvrDeviceByDeviceId(deviceChannel.getDeviceId(), deviceChannel.getChannelId());
        // 指定超时时间 1分钟30秒
        String uuid = UUID.randomUUID().toString();
        int sn = (int) ((Math.random() * 9 + 1) * 100000);
        String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + device.getDeviceId() + sn;
        RequestMessage msg = new RequestMessage();
        msg.setId(uuid);
        msg.setKey(key);
        try {
            // customName 为硬盘录像机对应的摄像机通道
            cmder.recordInfoQuery(device, device.getCustomName(), beginTime, endTime, sn, null, null, null,
                    (eventResult -> {
                        WVPResult<RecordInfo> wvpResult = new WVPResult<>();
                        wvpResult.setCode(ErrorCode.ERROR100.getCode());
                        wvpResult.setMsg("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg);
                        msg.setData(wvpResult);
                        resultHolder.invokeResult(msg);
                    }));
        } catch (InvalidArgumentException | SipException | ParseException e) {
            logger.error("[命令发送失败] 查询录像: {}", e.getMessage());
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
        }

        // 录像查询以channelId作为deviceId查询
        resultHolder.put(key, uuid, result);
        result.onTimeout(() -> {
            msg.setData("timeout");
            WVPResult<RecordInfo> wvpResult = new WVPResult<>();
            wvpResult.setCode(ErrorCode.ERROR100.getCode());
            wvpResult.setMsg("timeout");
            msg.setData(wvpResult);
            resultHolder.invokeResult(msg);
        });

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        RecordInfo recordInfo = BeanUtil.toBean(result.getResult(), RecordInfo.class);
        List<RecordItem> recordList = recordInfo.getRecordList();
        int index = NumberUtil.parseInt(FromIndex);
        int toIndex = Math.min(NumberUtil.parseInt(ToIndex), recordList.size());
        // 使用subList方法获取子列表
        List<RecordItem> channels = recordList.subList(index, toIndex);
        StringBuffer catalogXml = new StringBuffer();
        catalogXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n")
                .append("<SIP_XML EventType=\"Response_History_Video\">\r\n")
                .append("<SubList  RealNum=\"" + channels.size() + "\" SubNum=\"" + channels.size() + "\"" +
                        " FromIndex=\"" + FromIndex + "\" ToIndex=\"" + ToIndex + "\">\r\n");
        if (channels.size() > 0) {
            for (RecordItem recordItem : channels) {
                String startTime = recordItem.getStartTime();
                String endTime1 = recordItem.getEndTime();

                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime startDate = LocalDateTime.parse(startTime, formatter);
                // 将LocalDate转换为ZonedDateTime（UTC时区）
                ZonedDateTime zonedStartDate = startDate.atZone(ZoneId.of("UTC"));
                Instant startInstant = zonedStartDate.toInstant();
                String isoStartInstantStr = startInstant.toString();

                LocalDateTime endDate = LocalDateTime.parse(endTime1, formatter);
                // 将LocalDate转换为ZonedDateTime（UTC时区）
                ZonedDateTime zonedEndDate = endDate.atZone(ZoneId.of("UTC"));
                Instant endInstant = zonedEndDate.toInstant();
                String isoEndInstantStr = endInstant.toString();

//                String uuid1 = UUID.randomUUID().toString();
//                String key1 = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceChannel.getDeviceId() + deviceChannel.getChannelId();
//                DeferredResult<WVPResult<StreamContent>> result1 = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
//                resultHolder.put(key1, uuid1, result);
//
//                WVPResult<StreamContent> wvpResult = new WVPResult<>();
//
//                RequestMessage msg1 = new RequestMessage();
//                msg.setKey(key);
//                msg.setId(uuid);
//
//
//                this.playBack(deviceChannel.getDeviceId(), deviceChannel.getChannelId(), startTime, endTime, null,
//                        playBackResult->{
//                            wvpResult.setCode(playBackResult.getCode());
//                            wvpResult.setMsg(playBackResult.getMsg());
//                            if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {
//                                StreamInfo streamInfo = (StreamInfo)playBackResult.getData();
//                                wvpResult.setData(new StreamContent(streamInfo));
//                            }
//                            msg1.setData(wvpResult);
//                            resultHolder.invokeResult(msg1);
//                        });
//                try {
//                    Thread.sleep(2000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }

                catalogXml.append("<Item FileName=\"" + recordItem.getName() + "\" ");
                catalogXml.append("FileUrl=\"" + recordItem.getFilePath() + "\" ");
                catalogXml.append("BeginTime=\"" + isoStartInstantStr + "\" ");
                catalogXml.append("EndTime=\"" + isoEndInstantStr + "\" ");
                catalogXml.append("Size=\"" + recordItem.getFileSize() + "\" ");
                catalogXml.append("DecoderTag=\"" + "1111111100111000" + "\" ");
                catalogXml.append("Type=\"" + "2" + "\"/>\r\n ");
            }
        }
        catalogXml.append("</SubList>\r\n");
        catalogXml.append("</SIP_XML>\r\n");
        return catalogXml.toString();
    }


    /**
     * 向上级回复DeviceStatus查询信息
     *
     * @param parentPlatform 平台信息
     * @param sn
     * @param fromTag
     * @return
     */
    @Override
    public void deviceStatusResponse(ParentPlatform parentPlatform, String channelId, String sn, String fromTag, boolean status) throws SipException, InvalidArgumentException, ParseException {
        if (parentPlatform == null) {
            return;
        }
        String statusStr = (status) ? "ONLINE" : "OFFLINE";
        String characterSet = parentPlatform.getCharacterSet();
        StringBuffer deviceStatusXml = new StringBuffer(600);
        deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n")
                .append("<Response>\r\n")
                .append("<CmdType>DeviceStatus</CmdType>\r\n")
                .append("<SN>" + sn + "</SN>\r\n")
                .append("<DeviceID>" + channelId + "</DeviceID>\r\n")
                .append("<Result>OK</Result>\r\n")
                .append("<Online>" + statusStr + "</Online>\r\n")
                .append("<Status>OK</Status>\r\n")
                .append("</Response>\r\n");

        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(), parentPlatform.getTransport());

        Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceStatusXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader);
        sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);
    }


    @Override
    public void sendAlarmMessage(ParentPlatform parentPlatform, List<DeviceAlarm> deviceAlarms) throws SipException, InvalidArgumentException, ParseException {
        if (parentPlatform == null) {
            return;
        }
        String characterSet = parentPlatform.getCharacterSet();
        StringBuffer alertXml = new StringBuffer(600);

        alertXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n")
                .append("<SIP_XML EventType=\"Response_History_Alarm\">\r\n")
                .append("<SubList  RealNum=\"" + deviceAlarms.size() + "\" SubNum=\"" + deviceAlarms.size() + "\"" +
                        " FromIndex=\"" + 1 + "\" ToIndex=\"" + deviceAlarms.size() + "\">\r\n");

        for (DeviceAlarm deviceAlarm : deviceAlarms) {
            alertXml.append("<Item Code=\"" + deviceAlarm.getChannelId() + "\" ");
            alertXml.append("BeginTime=\"" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "\" ");
            alertXml.append("Status=\"" + 1 + "\" ");
            alertXml.append("Type=\"" + deviceAlarm.getAlarmType() + "\"/>\r\n ");
        }


        alertXml.append("</SubList>\r\n");
        alertXml.append("</SIP_XML>\r\n");

        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(), parentPlatform.getTransport());

        Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, alertXml.toString(), SipUtils.getNewFromTag(), SipUtils.getNewViaTag(), callIdHeader);
        sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);

    }

    @Override
    public void snapImageAndsendNoticeMsg(String deviceid, String PicServer, ParentPlatform parentPlatform, @Nullable SipTransactionInfo sipTransactionInfo) throws SipException, InvalidArgumentException, ParseException {
        //(1)调用接口进行视频截图，并保存到目录中，同时在redis保存截图信息
        String ffmpegpath = userSetting.getFfmpegpath();
        String channelid = deviceid;
        List<DeviceChannel> channels = channelMapper.queryAllChannels(deviceid);//获取一个默认通道
        if (channels.size() > 0) {
            channelid = channels.get(0).getChannelId();
        }
        String videoUrl = String.format("rtsp://%s:554/rtp/%s_%s", parentPlatform.getDeviceIp(), deviceid, channelid);
        // 获取当前日期时间
        LocalDateTime currentDateTime = LocalDateTime.now();
        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
        // 格式化日期时间
        String formattedDateTime = currentDateTime.format(formatter);
        String imagefilename = deviceid + "_" + formattedDateTime + ".jpg";
        VideoToImageUtil.getVideoPicture(ffmpegpath, videoUrl, userSetting.getSnapfilepath() + imagefilename);
        // 保存文件信息
        List<Map<String, String>> items = new ArrayList<>();
        File directory = new File(userSetting.getSnapfilepath());
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isFile()) {
                        Map<String, String> imageInfo = new HashMap<String, String>();
                        String itemCode = deviceid; // 你的前端设备地址编码
                        String fileType = "0"; // 文件类型，0表示图片
                        String time = file.getName().split(".")[0].split("_")[1]; // 解析获取文件时间
                        String fileUrl = "http://" + parentPlatform.getDeviceIp() + ":8080/download/" + file.getName(); // 抓拍图片的下载地址
                        String fileSize = String.valueOf(file.length()); // 文件大小，单位:字节
                        // 计算SHA-256校验和
                        String verify = null;
                        try {
                            verify = calculateSHA256(file);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        imageInfo.put("Item Code", itemCode);
                        imageInfo.put("Type", fileType);
                        imageInfo.put("Time", time);
                        imageInfo.put("FileUrl", fileUrl);
                        imageInfo.put("FileSize", fileSize);
                        imageInfo.put("Verify", verify);
                        items.add(imageInfo);
                    }
                }
            }
        }

        //(2)调用http接口上传截图文件,
        try {
            boolean ok = HttpUtils.uploadFile(PicServer, userSetting.getSnapfilepath() + imagefilename);
            if (!ok) {
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //(3)调用Notice命令发送通知
        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(), parentPlatform.getTransport());
        String fromTag = SipUtils.getNewFromTag();
        String toTag = null;
        if (sipTransactionInfo != null) {
            if (sipTransactionInfo.getCallId() != null) {
                callIdHeader.setCallId(sipTransactionInfo.getCallId());
            }
            if (sipTransactionInfo.getFromTag() != null) {
                fromTag = sipTransactionInfo.getFromTag();
            }
            if (sipTransactionInfo.getToTag() != null) {
                toTag = sipTransactionInfo.getToTag();
            }
        }
        StringBuffer catalogXml = new StringBuffer();
        catalogXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n")
                .append("<SIP_XML EventType=\"Snapshot_Notify\">\r\n");
        if (items.size() > 0) {
            for (Map<String, String> item : items) {
                catalogXml.append("<Item Code=\"" + item.get("Code") + "\" ");
                catalogXml.append("Type=\"" + item.get("Type") + "\" ");
                catalogXml.append("Time=\"" + item.get("Time") + "\" ");
                catalogXml.append("FileUrl=\"" + item.get("FileUrl") + "\" ");
                catalogXml.append("FileSize=\"" + item.get("FileSize") + "\" ");
                catalogXml.append("Verfiy=\"" + item.get("Verfiy") + "\"/>\r\n ");
            }
        }
        catalogXml.append("</SIP_XML>\r\n");

        Request request = headerProviderPlatformProvider.createNoticeRequest2(parentPlatform, catalogXml.toString(), fromTag, SipUtils.getNewViaTag(), toTag, callIdHeader);
        sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);

        //(4)文件上传成功后，并发送了通知信息后，删除截图文件
        String filePath = userSetting.getSnapfilepath() + imagefilename;
        File backupDir = new File(userSetting.getSnapfilepath(), "backup");
        if (!backupDir.exists() && !backupDir.mkdirs()) {
            backupDir.mkdirs();
        }
        String backfilePath = userSetting.getSnapfilepath() + "backup/" + imagefilename;

        File fileToDelete = new File(filePath);
        if (fileToDelete.exists()) {
            FileUtil.copy(filePath, backfilePath, true);//图片拷贝到备份目录下
            if (fileToDelete.delete()) {
                System.out.println("File deleted: " + filePath);
            } else {
                System.out.println("Failed to delete the file: " + filePath);
            }
        } else {
            System.out.println("File not found: " + filePath);
        }

    }

    @Override
    public void sendNotify(ParentPlatform parentPlatform,
                           SubscribeInfo subscribeInfo, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent)
            throws SipException, ParseException, InvalidArgumentException {
        MessageFactoryImpl messageFactory = (MessageFactoryImpl) SipFactory.getInstance().createMessageFactory();
        String characterSet = parentPlatform.getCharacterSet();
        // 设置编码， 防止中文乱码
        messageFactory.setDefaultContentEncodingCharset(characterSet);

        SIPRequest notifyRequest = headerProviderPlatformProvider.createNotifyRequest(parentPlatform, subscribeInfo);

        sipSender.transmitRequest(parentPlatform.getDeviceIp(), notifyRequest, errorEvent, okEvent);
    }


    @Override
    public void recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo) throws SipException, InvalidArgumentException, ParseException {
        if (parentPlatform == null) {
            return;
        }
        logger.info("[国标级联] 发送录像数据通道： {}", recordInfo.getChannelId());
        String characterSet = parentPlatform.getCharacterSet();
        StringBuffer recordXml = new StringBuffer(600);
        recordXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n")
                .append("<Response>\r\n")
                .append("<CmdType>RecordInfo</CmdType>\r\n")
                .append("<SN>" + recordInfo.getSn() + "</SN>\r\n")
                .append("<DeviceID>" + deviceChannel.getChannelId() + "</DeviceID>\r\n")
                .append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n");
        if (recordInfo.getRecordList() == null) {
            recordXml.append("<RecordList Num=\"0\">\r\n");
        } else {
            recordXml.append("<RecordList Num=\"" + recordInfo.getRecordList().size() + "\">\r\n");
            if (recordInfo.getRecordList().size() > 0) {
                for (RecordItem recordItem : recordInfo.getRecordList()) {
                    recordXml.append("<Item>\r\n");
                    if (deviceChannel != null) {
                        recordXml.append("<DeviceID>" + deviceChannel.getChannelId() + "</DeviceID>\r\n")
                                .append("<Name>" + recordItem.getName() + "</Name>\r\n")
                                .append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n")
                                .append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n")
                                .append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n")
                                .append("<Type>" + recordItem.getType() + "</Type>\r\n");
                        if (!ObjectUtils.isEmpty(recordItem.getFileSize())) {
                            recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n");
                        }
                        if (!ObjectUtils.isEmpty(recordItem.getFilePath())) {
                            recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n");
                        }
                    }
                    recordXml.append("</Item>\r\n");
                }
            }
        }

        recordXml.append("</RecordList>\r\n")
                .append("</Response>\r\n");
        logger.info("[国标级联] 发送录像数据通道：{}, 内容： {}", recordInfo.getChannelId(), recordXml);
        // callid
        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(), parentPlatform.getTransport());

        Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, recordXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader);
        sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, null, eventResult -> {
            logger.info("[国标级联] 发送录像数据通道：{}, 发送成功", recordInfo.getChannelId());
        });

    }


    @Override
    public void streamByeCmd(ParentPlatform platform, String callId) throws SipException, InvalidArgumentException, ParseException {
        if (platform == null) {
            return;
        }
        SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platform.getServerGBId(), null, null, callId);
        if (sendRtpItem != null) {
            streamByeCmd(platform, sendRtpItem);
        }
    }

    @Override
    public void streamByeCmd(ParentPlatform parentPlatform, SendRtpItem sendRtpItem) throws SipException, InvalidArgumentException, ParseException {
        if (sendRtpItem == null) {
            logger.info("[向上级发送BYE]， sendRtpItem 为NULL");
            return;
        }
        if (parentPlatform == null) {
            logger.info("[向上级发送BYE]， platform 为NULL");
            return;
        }
        logger.info("[向上级发送BYE]， {}/{}", parentPlatform.getServerGBId(), sendRtpItem.getChannelId());
        String mediaServerId = sendRtpItem.getMediaServerId();
        MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
        if (mediaServerItem != null) {
            mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc());
            zlmServerFactory.closeRtpServer(mediaServerItem, sendRtpItem.getStreamId());
        }
        SIPRequest byeRequest = headerProviderPlatformProvider.createByeRequest(parentPlatform, sendRtpItem);
        if (byeRequest == null) {
            logger.warn("[向上级发送bye]：无法创建 byeRequest");
        }
        sipSender.transmitRequest(parentPlatform.getDeviceIp(), byeRequest);
    }

    private String calculateSHA256(File file) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] buffer = new byte[8192];
        int bytesRead;
        FileInputStream fis = new FileInputStream(file);

        while ((bytesRead = fis.read(buffer)) != -1) {
            digest.update(buffer, 0, bytesRead);
        }

        fis.close();

        // Convert the byte to hex format
        StringBuilder sb = new StringBuilder();
        for (byte b : digest.digest()) {
            sb.append(String.format("%02x", b));
        }

        return sb.toString();
    }


    @Override
    public void sendAlarmNotice(ParentPlatform parentPlatform, List<Map<String, String>> alarmitems, @Nullable SipTransactionInfo sipTransactionInfo) throws InvalidArgumentException, ParseException, SipException {
        if (parentPlatform == null) {
            return;
        }
        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(), parentPlatform.getTransport());
        String fromTag = SipUtils.getNewFromTag();
        String toTag = null;
        if (sipTransactionInfo != null) {
            if (sipTransactionInfo.getCallId() != null) {
                callIdHeader.setCallId(sipTransactionInfo.getCallId());
            }
            if (sipTransactionInfo.getFromTag() != null) {
                fromTag = sipTransactionInfo.getFromTag();
            }
            if (sipTransactionInfo.getToTag() != null) {
                toTag = sipTransactionInfo.getToTag();
            }
        }
        StringBuffer Xml = new StringBuffer();
        Xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n")
                .append("<SIP_XML EventType=\"Notify_Alarm\">\r\n");
        if (alarmitems.size() > 0) {
            for (Map item : alarmitems) {
                Xml.append("<Item Code=\"" + item.get("Code").toString() + "\" ");
                Xml.append("Name=\"" + item.get("Name").toString() + "\" ");
                Xml.append("Type=\"" + item.get("Type").toString() + "\" ");
                Xml.append("StartTime=\"" + item.get("StartTime").toString() + "\"/>\r\n ");
            }
        }
        Xml.append("</SIP_XML>\r\n");

        Request request = headerProviderPlatformProvider.createNoticeRequest2(parentPlatform, Xml.toString(), fromTag, SipUtils.getNewViaTag(), toTag, callIdHeader);
        sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);
    }

    @Override
    public void sendDeviceStatusNotice(ParentPlatform parentPlatform, List<Map<String, String>> devicestatus, @Nullable SipTransactionInfo sipTransactionInfo) throws InvalidArgumentException, ParseException, SipException {
        if (parentPlatform == null) {
            return;
        }
        CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(), parentPlatform.getTransport());
        String fromTag = SipUtils.getNewFromTag();
        String toTag = null;
        if (sipTransactionInfo != null) {
            if (sipTransactionInfo.getCallId() != null) {
                callIdHeader.setCallId(sipTransactionInfo.getCallId());
            }
            if (sipTransactionInfo.getFromTag() != null) {
                fromTag = sipTransactionInfo.getFromTag();
            }
            if (sipTransactionInfo.getToTag() != null) {
                toTag = sipTransactionInfo.getToTag();
            }
        }
        StringBuffer Xml = new StringBuffer();
        Xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n")
                .append("<SIP_XML EventType=\"Notify_Status\">\r\n");
        if (devicestatus.size() > 0) {
            for (Map item : devicestatus) {
                Xml.append("<Item Code=\"" + item.get("Code").toString() + "\" ");
                Xml.append("Name=\"" + item.get("Name").toString() + "\" ");
                Xml.append("Status=\"" + item.get("Status").toString() + "\"/>\r\n ");
            }
        }
        Xml.append("</SIP_XML>\r\n");

        Request request = headerProviderPlatformProvider.createNoticeRequest2(parentPlatform, Xml.toString(), fromTag, SipUtils.getNewViaTag(), toTag, callIdHeader);
        sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);
    }
}
