package com.platform.modules.live.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.platform.common.annotation.SysLog;
import com.platform.common.utils.R;
import com.platform.common.utils.RedisUtils;
import com.platform.modules.live.constants.SceneConstants;
import com.platform.modules.live.dto.PushStreamNotifyDto;
import com.platform.modules.live.dto.TranscodeCompleteDto;
import com.platform.modules.live.entity.*;
import com.platform.modules.live.service.*;
import com.platform.modules.qk.service.VideoService;
import com.platform.plugs.live.LiveClient;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;

/**
 * @author TONG
 * 2019/2/16 15:46
 **/
@RestController
@RequestMapping("/live/notify")
public class LiveNotifyController {

    private final Log log = LogFactory.getLog(LiveNotifyController.class);

    private BlockingQueue<String> notifyQueue;

    public LiveNotifyController() {
        this.notifyQueue = new LinkedBlockingQueue<>();
        new Thread(() -> {// 顺序处理回调，避免错乱
            log.info("处理 VOD 回调线程开启");
            while (true) {
                try {
                    String notifyMessage = notifyQueue.take();
                    log.info("取出队列消息：" + notifyMessage);
                    this.vodNotifyAsyncHandler(notifyMessage);
                } catch (Exception e) {
                    log.error("处理 VOD 回调失败,进程将在 1S 后重新执行, exception : " + e.getMessage());
                    e.printStackTrace();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }, "VOD 回调线程").start();
    }

    @Autowired
    private LiveMultimediaService liveMultimediaService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private LiveClient liveClient;

    @Autowired
    private VideoService videoService;

    @Autowired
    private LiveStreamStatusService liveStreamStatusService;

    @Autowired
    private LiveTaskAllocationService taskAllocationService;

    @Autowired
    private LiveSceneRecordService liveSceneRecordService;

    @SysLog("推流状态回调函数")
    @GetMapping("/pushStreamStatus")
    public void pushStreamStatus(PushStreamNotifyDto dto) {
        log.info("流状态回调：" + dto.toString());
        LiveStreamStatusEntity liveStreamStatusEntity = new LiveStreamStatusEntity(dto.getTime(), dto.getAction(), dto.getApp(), dto.getAppname(), dto.getId(), dto.getNode(), dto.getIP(), dto.getUsrargs());
        //保存状态
        liveStreamStatusService.process(liveStreamStatusEntity);
    }

    @SysLog("现场录制保存至oss完成回调函数")
    @PostMapping("/recordFinish")
    public int recordFinish(HttpServletRequest request) {

        String msg = this.readNotifyMsgFromRequest(request);
        if (StringUtils.isBlank(msg)) {
            log.error("liveRecordController recordFinish notify error : no message");
            return 500;
        }
        log.info(msg);
        JSONObject json = JSONObject.parseObject(msg);
        if (!json.containsKey("domain") || !json.containsKey("app") || !json.containsKey("stream")) {
            log.error("liveRecordController recordFinish notify error : Illegal request : msg" + msg);
            return 500;
        }
        String domain = json.getString("domain");
        String appName = json.getString("app");
        String streamName = json.getString("stream");
        if (json.containsKey("uri") && json.containsKey("duration") && json.containsKey("start_time") && json.containsKey("stop_time")) {//录制成功
            LiveSceneLiveInfoRecordEntity record = new LiveSceneLiveInfoRecordEntity();
            record.setDomain(domain);
            record.setAppName(appName);
            record.setStreamName(streamName);
            record.setUri(json.getString("uri"));
            record.setDuration(json.getDouble("duration"));
            record.setStartTime(json.getInteger("start_time"));
            record.setStopTime(json.getInteger("stop_time"));
//                liveSceneLiveInfoService.saveLiveInfoRecord(record);
        } else if (json.containsKey("event")) {//录制状态变更

        } else {//非法
            log.error("liveRecordController recordFinish notify error : Illegal request : msg" + msg);
            return 500;
        }
//            System.out.println("recordFinish : " + msg);
        return 200;
    }

    @SysLog("导播台回调")
    @PostMapping("/caster")
    public void casterNotify(HttpServletRequest request) {

        String msg = this.readNotifyMsgFromRequest(request);
        if (StringUtils.isBlank(msg)) {
            log.error("notify error : no message");
            return;
        }
        log.info(msg);
        System.out.println(msg);
        JSONObject json = JSONObject.parseObject(msg);
        if (!json.containsKey("CasterId") || !json.containsKey("EventMessage") || !json.containsKey("EventType")) {
            log.error("casterNotify error : Illegal request : msg" + msg);
            return;
        }
        String casterId = json.getString("CasterId");
        String eventType = json.getString("EventType");
        if ("OperateCallback".equals(eventType)) {
            JSONObject eventMessageJson = json.getJSONObject("EventMessage");
            if (!eventMessageJson.containsKey("Code") || !eventMessageJson.containsKey("RequestId")) {
                log.error("casterNotify error : Illegal eventMessage : msg" + eventMessageJson.toString());
                return;
            }
            String code = eventMessageJson.getString("Code");
            if (!"Success".equals(code)) {
                log.error("casterNotify error : code : " + code + " : message" + eventMessageJson.getString("Message"));
                return;
            }
            String requestId = eventMessageJson.getString("RequestId");
            String key = "copyCasterSceneConfig_" + requestId + "_" + casterId;
            String value = redisUtils.get(key);
            if (StringUtils.isNotBlank(value)) {
                System.out.println(value);
                String appName = value.split(",")[0];
                String streamName = value.split(",")[1];
                System.out.println(appName);
                System.out.println(streamName);
                liveClient.liveRecord().addLiveRecordVodMp4Config(appName, streamName);
                liveClient.liveRecord().startRealTimeRecordCommand(appName, streamName);
            }
            redisUtils.delete(key);
        }
    }


    @SysLog("媒资库回调函数")
    @PostMapping("/VoDFinish")
    public void VoDFinish(HttpServletRequest request) {
        String msg = this.readNotifyMsgFromRequest(request);
        if (StringUtils.isBlank(msg)) {
            log.error("notify error : no message");
            return;
        }
        this.notifyQueue.add(msg);
    }

    private void vodNotifyAsyncHandler(String msg) throws ClientException {


        JSONObject json = JSONObject.parseObject(msg);
        String eventType = json.getString("EventType");
        String status = json.getString("Status");
        String videoId = json.getString("VideoId");
        String imageId = json.getString("ImageId");
        String mediaId = json.getString("MediaId");
        if (StringUtils.isBlank(eventType) || StringUtils.isBlank(videoId) && StringUtils.isBlank(imageId) && StringUtils.isBlank(mediaId)) {
            log.error("notify error : Illegal request : msg" + msg);
            return;
        }

        if (!"FileUploadComplete".equals(eventType) && !"ImageUploadComplete".equals(eventType) && !"UploadByURLComplete".equals(eventType) && StringUtils.isBlank(status)) {
            log.error("notify error : unsuccess request : msg :" + msg);
            return;
        }
        //FileUploadComplete ImageUploadComplete UploadByURLComplete 无status
        //由于合成自定义失效，合成成功后系统会调用FileUploadComplete，所以先把FileUploadComplete打开
        if ("FileUploadComplete".equals(eventType)) {

        } else if (!"success".equals(status)) {
            log.error("notify error : VoDFinish , status : " + status + ", videoId : " + videoId + ", eventType : " + eventType);
            return;
        }
        switch (eventType) {
            case "MediaBaseChangeComplete": //媒资基础信息变更，素材库中添加此记录

                break;
            case "FileUploadComplete"://视频上传完成 or 媒体合成
//                videoService.produceMediaComplete(videoId);
                if (!json.containsKey("FileUrl")) {
                    log.error("notify error : FileUploadComplete , FileUrl is null");
                    return;
                }
                String fileUrl = json.getString("FileUrl");
                Long size = 0L;
                if (json.containsKey("Size"))
                    size = json.getLong("Size");
                liveMultimediaService.updateOriMediaUrl(videoId, fileUrl, size);
                break;
            case "ImageUploadComplete"://图片上传完成
                liveMultimediaService.getImageInfo(imageId);
                break;
            case "UploadByURLComplete"://URL上传视频完成
                break;
            case "SnapshotComplete"://视频截图完成
                liveMultimediaService.getVideoInfo(videoId);
                break;
            case "VideoAnalysisComplete"://音视频分析完成
                liveMultimediaService.videoAnalysisComplete(videoId, json.getInteger("Width"), json.getInteger("Height"), json.getFloat("Duration"), json.getString("Bitrate"), json.getString("Fps"), json.getLong("Size"));
                break;
            case "AddLiveRecordVideoComplete"://直转点视频录制完成
                liveMultimediaService.addLiveRecordVideoComplete(videoId, json.getString("DomainName"), json.getString("AppName"), json.getString("StreamName"), json.getString("RecordStartTime"), json.getString("RecordEndTime"), json.getString("EventTime"));
                break;
            case "LiveRecordVideoComposeStart"://直转点录制视频合成开始
                break;
            case "ProduceMediaComplete"://媒体合成完成
                videoService.produceMediaComplete(mediaId);
                break;
            case "StreamTranscodeComplete"://视频单个清晰度转码完成
                // 目前只转码一种格式，故暂不处理，若多个转码格式需在此处理

                break;
            case "TranscodeComplete"://视频全部清晰度转码完成
                if (!json.containsKey("StreamInfos")) {
                    log.error("notify error : VoDFinish : StreamInfos is null");
                }
                JSONArray array = json.getJSONArray("StreamInfos");
                if (array != null && array.size() > 0) {
                    JSONObject record = null;
                    for (int index = 0; index < array.size(); index++) {
                        record = array.getJSONObject(index);// TODO 取第一个取mp3/mp4的记录
                        String format = record.getString("Format");
                        if (!"mp4".equals(format) && !"mp3".equals(format))//取mp3/mp4的录制
                            continue;
                        break;
                    }
                    TranscodeCompleteDto transcodeCompleteDto = JSONObject.parseObject(record.toJSONString(), TranscodeCompleteDto.class);
                    liveMultimediaService.transcodeComplete(videoId, transcodeCompleteDto);
                }
                break;
            case "CreateAuditComplete"://人工审核完成
                break;
            case "AIMediaAuditComplete"://智能审核完成
                break;
            case "AIMediaDNAComplete"://视频DNA完成
                break;
            default:
                break;
        }
    }

    private String readNotifyMsgFromRequest(HttpServletRequest request) {
        Object json = request.getAttribute(SceneConstants.LIVENOTIFY_REQUESTMSG);
        if (json != null)
            return json.toString();
        return null;
    }

    @SysLog("语音转文字回调")
    @PostMapping("/allocation")
    public void allocationCallback(HttpServletRequest request) {

        System.out.println("语音转文字回调开始,开始时间为：" + new Date().getTime());

        String msg = this.readNotifyMsgFromRequest(request);

        if (StringUtils.isBlank(msg)){
            log.error("notify error : no message");
            return;
        }

        JSONObject jsonResult = JSONObject.parseObject(msg);
        if (null == jsonResult){
            log.error("notify error : no message");
            return;
        }
        String taskId = jsonResult.getString("TaskId");
        String statusCode = jsonResult.getString("StatusCode");
        StringBuilder text = new StringBuilder();
        Double durationTime = null;

        if ("21050000".equals(statusCode)) {
            durationTime = Double.valueOf(jsonResult.getString("BizDuration"));
            for (int i = 0; i < jsonResult.getJSONObject("Result").getJSONArray("Sentences").size(); i++) {
                text.append(jsonResult.getJSONObject("Result").getJSONArray("Sentences").getJSONObject(i).getString("Text"));
            }
        }else {
            log.error(jsonResult.getString("StatusText"));
        }

        System.out.println("语音转文字回调结束,结束时间为：" + new Date().getTime());
        System.out.println("语音转文字解析内容为：" + text.toString());

        // 保存信息
        List<LiveTaskAllocationEntity> taskAllocationEntityList = taskAllocationService.selectList(
                new EntityWrapper<LiveTaskAllocationEntity>().eq("task_id", taskId)
        );

        if (null != taskAllocationEntityList && taskAllocationEntityList.size() > 0){
            for (LiveTaskAllocationEntity entity : taskAllocationEntityList){
                entity.setDurationTime(null == durationTime ? entity.getDurationTime() : String.valueOf((durationTime / 1000)));
                entity.setText(text.toString());
            }
            taskAllocationService.updateBatchById(taskAllocationEntityList);
        }
    }

    @SysLog
    @PostMapping("/voiceToText")
    public void voiceToTextCallback(HttpServletRequest request){

        System.out.println("语音转文字回调开始,开始时间为：" + new Date().getTime());

        String msg = this.readNotifyMsgFromRequest(request);

        if (StringUtils.isBlank(msg)){
            log.error("notify error : no message");
            return;
        }

        JSONObject jsonResult = JSONObject.parseObject(msg);
        if (null == jsonResult){
            log.error("notify error : no message");
            return;
        }
        String taskId = jsonResult.getString("TaskId");
        String statusCode = jsonResult.getString("StatusCode");
        StringBuilder text = new StringBuilder();

        if ("21050000".equals(statusCode)) {
            for (int i = 0; i < jsonResult.getJSONObject("Result").getJSONArray("Sentences").size(); i++) {
                text.append(jsonResult.getJSONObject("Result").getJSONArray("Sentences").getJSONObject(i).getString("Text"));
            }
        }else {
            log.error(jsonResult.getString("StatusText"));
        }

        System.out.println("语音转文字回调结束,结束时间为：" + new Date().getTime());
        System.out.println("语音转文字解析内容为：" + text.toString());

        // 保存素材信息
        LiveSceneRecordEntity liveSceneRecordEntity = liveSceneRecordService.selectOne(new EntityWrapper<LiveSceneRecordEntity>().eq("task_id", taskId));

        if (liveSceneRecordEntity == null){
            log.error("notify error : no message");
            return;
        }

        liveSceneRecordEntity.setText(text.toString());
        liveSceneRecordEntity.setToTxtStatus(1);

        liveSceneRecordService.updateById(liveSceneRecordEntity);
    }
}
