package com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.request.LocusDataRequest;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.TunnelDetailService;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.TunnelDeviceService;
import com.cico.nest.lcdp.boot.core.qxsd.domain.gateway.HistoryGateway;
import com.cico.nest.lcdp.boot.core.qxsd.domain.gateway.VehicleGateway;
import com.cico.nest.lcdp.boot.core.qxsd.domain.vehicle.HistoryTunnelVehicle;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.common.result.HkVideoResultData;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.common.result.XlwResultData;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.convertor.VehicleConvertor;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.TunnelDeviceMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.TunnelEquipmentMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.TunnelDeviceDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.TunnelEquipmentDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.http.HistoryMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.http.hk.HkVideoMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.http.xlw.dto.XlwHolographicTimeHistoryDTO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.ws.xlw.dto.XlwRealTimeVehicleDTO;
import com.cico.nest.lcdp.boot.core.system.dal.dataobject.social.SocialUserDO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author zws
 * @date 2024/8/20
 */

@Slf4j
@Service
public class HistoryGatewayImpl implements HistoryGateway {
    @Resource
    private HistoryMapper historyMapper;
    @Resource
    private VehicleGateway vehicleGateway;
    @Resource
    private TunnelDeviceMapper tunnelDeviceMapper;
    @Resource
    private HkVideoMapper hkVideoMapper;
    @Value("${qxsd.video.eventHisSavePath}")
    private String eventHisSaveVideoPath;

    @Override
    public String saveEventImage(String urlPath) {
        return historyMapper.saveEventImage(urlPath);
    }

    @Override
    public List<String> saveBayonetImage(String carPlate, Date eventStartTime) {
        return historyMapper.saveBayonetImage(carPlate,eventStartTime);
    }



    @Override
    public TunnelDeviceDO getDevice(String tunnelCode,String holeId,Integer deviceMilestone,Integer direction) {
        TunnelDeviceDO tunnelDeviceDO = tunnelDeviceMapper.selectOne(new LambdaQueryWrapper<TunnelDeviceDO>()
                        .eq(TunnelDeviceDO::getTunnelCode, tunnelCode)
                        .eq(TunnelDeviceDO::getHoleId, holeId)
                        .eq(TunnelDeviceDO::getDirectionUpdown, direction)
                        .eq(TunnelDeviceDO::getCameraLable, 1)
                        .gt(TunnelDeviceDO::getMileStart, deviceMilestone)
                ,false);
        // 摄像头 查询几个点
        // 同一个tunnel_code，hole_id，上下行方向：100700上行/100701下行
        // camera_lable(摄像机标签) = 1(全息相机)
        // deviceMilestone:215838,direction:100700
        // 条件是lt 查询到的: 215700  < 215838
        // 条件是gt 查询到的: 216100  > 215838
        // 小于号是这样表示的：&lt   ；大于号是这样表示的：&gt  ;
        // todo 是否需要判断超出最大桩号？
        return tunnelDeviceDO;
    }

    @Override
    public String saveVideo(String cameraIndexCode,String beginTime,String endTime,String outputFile) {
        String hkVideoResultDataStr = hkVideoMapper.getPlaybackURLs(cameraIndexCode,beginTime,endTime);
        HkVideoResultData hkVideoResultData = JSONObject.parseObject(hkVideoResultDataStr, HkVideoResultData.class);
        Object urlObject = hkVideoResultData.getData().get("url");
        if(Objects.nonNull(urlObject)){
            try {
                videoPuller(urlObject.toString(),eventHisSaveVideoPath + "/" + outputFile);
                return outputFile;
            } catch (Exception e) {
                return "error保存回放视频流失败";
            }
        }
        return "error获取回放视频流失败";
    }

    @Override
    public List<HistoryTunnelVehicle> getVehicleInfo(LocusDataRequest locusDataRequest) {
//        List<XlwHolographicTimeHistoryDTO> xlwHistoryEventList = historyMapper.getVehicleInfo(guid);
//        if(CollUtil.isEmpty(xlwHistoryEventList)){
//            log.error("获取事件全息回放数据为空，guid:{}", guid);
//            return new ArrayList<>();
//        }
//        return VehicleConvertor.convert2HistoryTunnelVehicle(xlwHistoryEventList,tunnelId,direction,startMilestone);
        // 2025-06 说让调用 4.5 todo
        return vehicleGateway.getCarLocusData(locusDataRequest);
    }

    @Override
    public  void videoPuller(String rtspUrl, String outputFile) {
        log.info("保存视频-保存切片视频:{},outputFile:{}",rtspUrl,outputFile);
        // 创建抓取器
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtspUrl);
        try {
            grabber.start();
            // 创建录制器-设置的文件保存位置以及视频画面的宽度和高度
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight());
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 设置视频编解码器
            recorder.setFormat("mp4"); // 设置视频输出格式
            // 设置音频相关参数
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
            recorder.setAudioChannels(2);
            recorder.setSampleRate(44100);
            recorder.setAudioBitrate(192000);
            recorder.start();
            Frame frame;
            while ((frame = grabber.grabFrame()) != null) {
                recorder.record(frame);
            }
            recorder.stop();
            grabber.stop();
            recorder.close();
            grabber.close();
        } catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
            e.printStackTrace();
        }
    }
}
