package com.sptg.video.cloud.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.sptg.common.core.beans.PageBean;
import com.sptg.common.core.beans.ResultBean;
import com.sptg.common.core.beans.ResultEnum;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.common.core.util.JsonUtils;
import com.sptg.video.cloud.api.beans.ApiResultBean;
import com.sptg.video.cloud.api.dto.VCDeviceDto;
import com.sptg.video.cloud.api.entity.VCApiLog;
import com.sptg.video.cloud.api.entity.VCDevice;
import com.sptg.video.cloud.api.entity.SysParams;
import com.sptg.video.cloud.api.beans.PageInfo;
import com.sptg.video.cloud.api.entity.VCPusherConfig;
import com.sptg.video.cloud.api.utils.VideoCloudHttpUtil;
import com.sptg.video.cloud.biz.mapper.VCDeviceMapper;
import com.sptg.video.cloud.biz.service.VCApiLogServiceInterface;
import com.sptg.video.cloud.biz.service.VCDeviceServiceInterface;
import com.sptg.video.cloud.biz.service.VCPusherConfigServiceInterface;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * @author zwx
 * @create 2020/10/16 12:36
 * 设备 服务层实现层
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VCDeviceServiceImpl extends ServiceImpl<VCDeviceMapper, VCDevice> implements VCDeviceServiceInterface {

    private final VCApiLogServiceInterface apiLogServiceInterface;
    private final VCPusherConfigServiceInterface vcPusherConfigServiceInterface;

    @Override
    public Page<VCDevice> pagingQuery(PageBean<VCDevice, VCDeviceDto> pageBean) {

        VCDeviceDto deviceDto = pageBean.getDto();
        //  排序字段 时间降序
        pageBean.setOrderByField("t_create_date").setAsc(false);
        // 构建查询条件
        Wrapper<VCDevice> wrapper = new EntityWrapper<>();

        if(null != deviceDto){
            //根据id查询
            if (deviceDto.getId() != null) {
                wrapper.eq("l_id", deviceDto.getId());
            }
            //根据设备名称查询
            if (StringUtils.isNotBlank(deviceDto.getDeviceName())) {
                wrapper.like("s_device_name", deviceDto.getDeviceName(), SqlLike.DEFAULT);
            }
            //根据名字设备号查询
            if (StringUtils.isNotBlank(deviceDto.getDeviceNum())) {
                wrapper.eq("s_device_num", deviceDto.getDeviceNum());
            }
            //根据机构树位置查询
            if (StringUtils.isNotBlank(deviceDto.getOrgPosition())) {
                wrapper.like("s_org_position", deviceDto.getOrgPosition(), SqlLike.RIGHT);
            }
            //根据设备类型查询
            if (deviceDto.getDeviceType() != null) {
                wrapper.eq("i_device_type", deviceDto.getDeviceType());
            }
            //根据在线状态查询
            if (deviceDto.getIsOnline() != null) {
                wrapper.eq("i_is_online", deviceDto.getIsOnline());
            }
            //根据告警状态
            if (deviceDto.getAlarmStatus() != null) {
                wrapper.eq("i_alarm_status", deviceDto.getAlarmStatus());
            }
            //根据推流状态
            if (deviceDto.getPusherStatus() != null) {
                wrapper.eq("i_pusher_status", deviceDto.getPusherStatus());
            }
            //根据账号状态
            if (deviceDto.getAccountName() != null) {
                wrapper.like("s_account_name", deviceDto.getAccountName());
            }
        }

        //  查询设备列表
        Page<VCDevice> page = this.selectPage(pageBean, wrapper);
        return page;
    }

    @Override
    public List<VCDevice> getList() {
        Wrapper<VCDevice> wrapper = new EntityWrapper<>();
        return this.selectList(wrapper);
    }

    @Override
    public VCDevice findDeviceById(Long id) {
        Wrapper<VCDevice> wrapper = new EntityWrapper<>();
        wrapper.eq("l_id",id);
        return this.selectOne(wrapper);
    }

    @Override
    public VCDevice findDeviceByNum(String deviceNum) {
        Wrapper<VCDevice> wrapper = new EntityWrapper<>();
        wrapper.eq("s_device_num", deviceNum);
        return this.selectOne(wrapper);
    }

    @Override
    public ResultBean<String> syncDeviceList(SysParams sysParams, VCDeviceDto deviceDto) {
        List<String> deviceNums = deviceDto.getDeviceNums();
        VideoCloudHttpUtil httpUtil = new VideoCloudHttpUtil(sysParams);
        List<VCDevice> vcDeviceList = new ArrayList<>();
        if(deviceNums != null && deviceNums.size() > 0){
            deviceNums.forEach(deviceNum -> {
                Map<String, Object> bizParamsMap = new HashMap<>();
                bizParamsMap.put("deviceNum", deviceNum);
                ApiResultBean<VCDevice> deviceApiResultBean = httpUtil.deviceGetList(bizParamsMap);
                if(deviceApiResultBean.getReturnCode().equals(OperationConstant.ONE + "")){
                    PageInfo<VCDevice> pageInfo = deviceApiResultBean.getPageInfo();
                    List<VCDevice> list = pageInfo.getList();
                    vcDeviceList.add(list.get(0));
                    VCApiLog apiLog = BeanUtil.copyProperties(deviceApiResultBean, VCApiLog.class);
                    String deviceApiResultBeanStr = JSONUtil.toJsonStr(deviceApiResultBean);
                    apiLog.setRespInfo(deviceApiResultBeanStr);
                    apiLog.setCreateDate(new Date());
                    apiLog.setDeviceNum(deviceNum);
                    apiLog.setAccountName(sysParams.getAccount());
                    apiLog.setApiMethodName("获取设备列表");
                    this.apiLogServiceInterface.insert(apiLog);
                }
            });
        }else{
            ApiResultBean<VCDevice> deviceApiResultBean = httpUtil.deviceGetList(null);
            if(deviceApiResultBean.getReturnCode().equals(OperationConstant.ONE + "")){
                List<VCDevice> list = deviceApiResultBean.getPageInfo().getList();
                list.forEach(device -> {
                    vcDeviceList.add(device);
                });
                VCApiLog apiLog = BeanUtil.copyProperties(deviceApiResultBean, VCApiLog.class);
                String deviceApiResultBeanStr = JSONUtil.toJsonStr(deviceApiResultBean);
                apiLog.setRespInfo(deviceApiResultBeanStr);
                apiLog.setCreateDate(new Date());
                apiLog.setAccountName(sysParams.getAccount());
                apiLog.setApiMethodName("获取设备列表");
                this.apiLogServiceInterface.insert(apiLog);
            }
        }
        List<VCDevice> updateVcDeviceList = new ArrayList<>();
        if(vcDeviceList.size() > 0){
            vcDeviceList.forEach(source -> {
                VCDevice target = null;
                target = this.findDeviceByNum(source.getDeviceNum());
                Date today = new Date();
                if(target == null){
                    target = new VCDevice();
                    target.setCreateDate(today);
                }else{
                    source.setId(target.getId());
                }
                BeanUtil.copyProperties(source, target);
                target.setAccountName(deviceDto.getAccountName());
                target.setUpdateDate(today);
                updateVcDeviceList.add(target);
            });
        }
        if(updateVcDeviceList.size() > 0){
            boolean result = this.insertOrUpdateBatch(updateVcDeviceList, 100);
            if(result){
                return new ResultBean<>(ResultEnum.SUCCESS, "同步成功");
            }else{
                return new ResultBean<>(ResultEnum.FAILURE, "同步成功，但保存失败");
            }
        }else{
            return new ResultBean<>(ResultEnum.FAILURE, "接口调用失败或无数据返回");
        }
    }

    @Override
    public String deviceGetDevUrl(SysParams sysParams, VCDeviceDto deviceDto) {
        VideoCloudHttpUtil httpUtil = new VideoCloudHttpUtil(sysParams);
        Map<String, Object> bizParamsMap = new HashMap<>();
        bizParamsMap.put("deviceNum", deviceDto.getDeviceNum());
        bizParamsMap.put("networkType", "1"); //TCP
        ApiResultBean apiResultBean = httpUtil.deviceGetDevUrl(bizParamsMap);
        VCApiLog apiLog = BeanUtil.copyProperties(apiResultBean, VCApiLog.class);
        String apiResultBeanStr = JSONUtil.toJsonStr(apiResultBean);
        apiLog.setRespInfo(apiResultBeanStr);
        apiLog.setCreateDate(new Date());
        apiLog.setDeviceNum(deviceDto.getDeviceNum());
        apiLog.setAccountName(sysParams.getAccount());
        apiLog.setApiMethodName("获取设备视频地址");
        this.apiLogServiceInterface.insert(apiLog);
        String rtspUrl = null;
        if(apiResultBean.getReturnCode().equals(OperationConstant.ONE + "")){
            rtspUrl = apiResultBean.getRtspUrl();
            VCDevice device = this.findDeviceByNum(deviceDto.getDeviceNum());
            device.setRtspUrl(rtspUrl);
            device.setUpdateDate(new Date());
            this.updateById(device);
        }else{
            VCDevice device = this.findDeviceByNum(deviceDto.getDeviceNum());
//            device.setRtspUrl("获取视频播放地址失败");
            device.setUpdateDate(new Date());
            this.updateById(device);
        }
        return rtspUrl;
    }

    @Async
    @Override
    public List<String> deviceGetDevUrlList(SysParams sysParams, String accountName) {
        Wrapper<VCDevice> wrapper = new EntityWrapper<>();
        wrapper.eq("s_account_name", accountName);
        List<VCDevice> vcDevices = this.selectList(wrapper);
        List<String> rtspUrlList = new ArrayList<>();
        vcDevices.forEach(vcDevice -> {
            VCDeviceDto deviceDto = new VCDeviceDto();
            deviceDto.setDeviceNum(vcDevice.getDeviceNum());
            String rtspUrl = this.deviceGetDevUrl(sysParams, deviceDto);
            rtspUrlList.add(rtspUrl);
        });
        return rtspUrlList;
    }

    @Override
    public ResultBean<String> deviceGetHttpFlvUrl(String deviceNum, String rtspUrl) {
        if (deviceNum != null) {
            // Nginx rtmp地址
            // 1935 对应Nginx配置文件中rtmp所监听的端口
            // myapp 对应Nginx配置文件中rtmp下application的值
            // rtmpStream 对应播放页面中16行参数stream的值
            String nginxRtmpUrl = "rtmp://192.168.0.228:1935/myapp/mystream-" + deviceNum;
            int flag = -1;
            try {
                // ffmpeg 已经在系统环境
                String command = "ffmpeg -rtsp_transport tcp";
                command += " -i " + rtspUrl;
                command += " -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -s 1280x720 -acodec aac -f flv " + nginxRtmpUrl;
                Process process = Runtime.getRuntime().exec(command);
                flag = process.waitFor();
                log.error("flag", flag);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if(flag != -1){
                String httpFlv = "http://139.9.103.171/live?port=1935&app=myapp&stream=mystream-" + deviceNum;
                return new ResultBean<>(ResultEnum.SUCCESS, httpFlv);
            }else{
                return new ResultBean<>(ResultEnum.FAILURE, null);
            }
        }else{
            return null;
        }
    }

    @Override
    public ResultBean<String> devicePusher(VCDeviceDto vcDeviceDto) {
        VideoCloudHttpUtil httpUtil = new VideoCloudHttpUtil(null);
        VCPusherConfig vcPusherConfig = this.vcPusherConfigServiceInterface.findById(1L);
        Map<String, Object> bizParamMap = new HashMap<>();
        bizParamMap.put("id", vcDeviceDto.getDeviceNum());
        bizParamMap.put("pushSrcUrl", vcDeviceDto.getRtspUrl());
        bizParamMap.put("pushDescUrl", vcPusherConfig.getPushDescUrl() + vcDeviceDto.getDeviceNum());
        String requstUrl = vcPusherConfig.getPusherUrl() + "/pushers";
        String s = httpUtil.devicePusher(bizParamMap, requstUrl);
        JSONObject jsonObject = JSONUtil.parseObj(s);
        Object data = jsonObject.get("data");
        JSONObject jsonObject1 = JSONUtil.parseObj(data);
        Integer workerStatus = (Integer)jsonObject1.get("workerStatus");
        if(workerStatus.equals(0) || workerStatus.equals(3)){
            return new ResultBean<>(ResultEnum.SUCCESS, "启动成功");
        }else{
            return new ResultBean<>(ResultEnum.SUCCESS, "启动失败");
        }
    }

    @Override
    public ResultBean<String> devicePusherStatus(VCDeviceDto deviceDto) {
        VideoCloudHttpUtil httpUtil = new VideoCloudHttpUtil(null);
        VCPusherConfig vcPusherConfig = this.vcPusherConfigServiceInterface.findById(1L);
        String requstUrl = vcPusherConfig.getPusherUrl() + "/pushers/status";
        String s = httpUtil.devicePusherStatus(deviceDto.getDeviceNum(), requstUrl);
        JSONObject jsonObject = JSONUtil.parseObj(s);
        Object data = jsonObject.get("data");
        JSONObject jsonObject1 = JSONUtil.parseObj(data);
        Integer workerStatus = (Integer)jsonObject1.get("workerStatus");
        VCDevice device = this.findDeviceByNum(deviceDto.getDeviceNum());
        device.setPusherStatus(workerStatus);
        this.updateById(device);
        if(workerStatus.equals(0)){
            return new ResultBean<>(ResultEnum.SUCCESS, "推流进行中");
        }else if(workerStatus.equals(1)){
            return new ResultBean<>(ResultEnum.SUCCESS, "不存在该流");
        }else {
            return new ResultBean<>(ResultEnum.SUCCESS, "等待调度推流中");
        }
    }

    @Override
    public ResultBean<String> devicePusherDelete(VCDeviceDto deviceDto) {
        VideoCloudHttpUtil httpUtil = new VideoCloudHttpUtil(null);
        VCPusherConfig vcPusherConfig = this.vcPusherConfigServiceInterface.findById(1L);
        String requstUrl = vcPusherConfig.getPusherUrl() + "/pushers";
        String s = httpUtil.devicePusherDelete(deviceDto.getDeviceNum(), requstUrl);
        JSONObject jsonObject = JSONUtil.parseObj(s);
        Object data = jsonObject.get("data");
        JSONObject jsonObject1 = JSONUtil.parseObj(data);
        Integer workerStatus = (Integer)jsonObject1.get("workerStatus");
        if(workerStatus.equals(2)){
            return new ResultBean<>(ResultEnum.SUCCESS, "停止成功");
        }else if(workerStatus.equals(1)){
            return new ResultBean<>(ResultEnum.SUCCESS, "不存在该流");
        }else {
            return new ResultBean<>(ResultEnum.SUCCESS, "不存在该流");
        }
    }
}
