package com.yeejoin.amos.boot.module.jcs.biz.audioToText;

import com.alibaba.nls.client.protocol.asr.SpeechTranscriberListener;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;
import org.typroject.tyboot.component.emq.EmqKeeper;

import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 实时语音识别 回调函数
 */
public class RealTimeSpeechTranscriberListener extends SpeechTranscriberListener {
    private static final Logger logger = LoggerFactory.getLogger(RealTimeSpeechTranscriberListener.class);
    public static final int RESULT_SUCCESS_CODE = 20000000;
    private final String myNumber;
    private final String typeNumber;
    private final EmqKeeper emqKeeper;
    private final List<AudioRecord> audioRecords;
    private final AudioKeyWord audioKeyWords;

    public RealTimeSpeechTranscriberListener(
            String myNumber,
            String typeNumber,
            EmqKeeper emqKeeper,
            List<AudioRecord> audioRecords,
            AudioKeyWord audioKeyWords) {
        this.myNumber = myNumber;
        this.typeNumber = typeNumber;
        this.emqKeeper = emqKeeper;
        this.audioRecords = audioRecords;
        this.audioKeyWords = audioKeyWords;
    }

    /**
     * 语音识别过程中返回的结果。仅当setEnableIntermediateResult为true时，才会返回该消息。
     */
    @Override
    public void onTranscriptionResultChange(SpeechTranscriberResponse response) {
        logger.warn("语音识别过程中返回的结果");
        logger.warn("task_id: " + response.getTaskId() +
                ", name: " + response.getName() +
                //状态码“20000000”表示正常识别。
                ", status: " + response.getStatus() +
                //句子编号，从1开始递增。
                ", index: " + response.getTransSentenceIndex() +
                //当前的识别结果。
                ", result: " + response.getTransSentenceText() +
                //当前已处理的音频时长，单位为毫秒。
                ", time: " + response.getTransSentenceTime());
        responseHandler(response);
    }


    /**
     * 服务端准备好了进行识别
     */
    @Override
    public void onTranscriberStart(SpeechTranscriberResponse response) {
        logger.warn("服务端准备好了进行识别");
        logger.warn("task_id: " + response.getTaskId()
                + ", name: " + response.getName()
                + ", status: " + response.getStatus());
    }

    /**
     * 服务端检测到了一句话的开始
     */
    @Override
    public void onSentenceBegin(SpeechTranscriberResponse response) {
        logger.warn("服务端检测到了一句话的开始");
        logger.warn("task_id: " + response.getTaskId()
                + ", name: " + response.getName()
                + ", status: " + response.getStatus());
    }

    /**
     * 服务端检测到了一句话的结束
     * 识别出一句话。服务端会智能断句，当识别到一句话结束时会返回此消息。
     */
    @Override
    public void onSentenceEnd(SpeechTranscriberResponse response) {
        logger.warn("服务端检测到了一句话的结束");
        logger.warn("task_id: " + response.getTaskId() +
                ", name: " + response.getName() +
                //状态码“20000000”表示正常识别。
                ", status: " + response.getStatus() +
                //句子编号，从1开始递增。
                ", index: " + response.getTransSentenceIndex() +
                //当前的识别结果。
                ", result: " + response.getTransSentenceText() +
                //置信度
                ", confidence: " + response.getConfidence() +
                //开始时间
                ", begin_time: " + response.getSentenceBeginTime() +
                //当前已处理的音频时长，单位为毫秒。
                ", time: " + response.getTransSentenceTime());
        responseHandler(response);
    }

    /**
     * 识别结束后返回的最终结果
     */
    @Override
    public void onTranscriptionComplete(SpeechTranscriberResponse response) {
        logger.warn("识别结束后返回的最终结果");
        logger.warn("task_id: " + response.getTaskId()
                + ", name: " + response.getName()
                + ", status: " + response.getStatus()
                + ",result:" + response.getTransSentenceText());
        try {
            emqKeeper.getMqttClient().publish(AudioTopic.RECORD.getName() + "/" + myNumber, "".getBytes(), 2, true);
            emqKeeper.getMqttClient().publish(AudioTopic.KEYWORD.getName() + "/" + myNumber, "".getBytes(), 2, true);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 失败处理
     */
    @Override
    public void onFail(SpeechTranscriberResponse response) {
        logger.error("失败处理");
        logger.error("task_id: " + response.getTaskId()
                + ", status: " + response.getStatus()
                + ", status_text: " + response.getStatusText());
    }

    private void responseHandler(SpeechTranscriberResponse response) {
        if (response.getStatus() == RESULT_SUCCESS_CODE) {
            AudioRecord audioRecord = new AudioRecord.AudioRecordBuilder()
                    .type(typeNumber)
                    .taskId(response.getTaskId())
                    .name(response.getName())
                    .status(response.getStatus())
                    .index(response.getTransSentenceIndex())
                    .message(response.getTransSentenceText())
                    .confidence(response.getConfidence())
                    .time(response.getTransSentenceTime())
                    .build();
            int index = audioRecord.getIndex() - 1;
            if (index >= audioRecords.size()) {
                audioRecords.add(audioRecord);
            } else {
                audioRecords.set(index, audioRecord);
            }
            sendRecord(audioRecord);
            sendKeyword();
        } else {
            logger.error("异常的相应结果，响应码：" + response.getStatus());
        }
    }

    /**
     * 异步发送结果至mqtt，保持回调函数畅通
     *
     * @param audioRecord 语音句子识别返回结果
     */
    @Async
    public void sendRecord(AudioRecord audioRecord) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            byte[] bytes = objectMapper.writeValueAsString(audioRecord).getBytes();
            emqKeeper.getMqttClient().publish(AudioTopic.RECORD.getName() + "/" + myNumber, bytes, 2, false);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("发送音频识别结果消息异常，原因：" + e.getMessage());
        }
    }

    /**
     * 异步发送结果至mqtt，保持回调函数畅通
     */
    @Async
    public void sendKeyword() {
        audioKeyWords.getValues().values().forEach(Set::clear);
        try {
            StringBuilder stringBuilder = new StringBuilder();
            audioRecords.forEach(audioRecord -> {
                stringBuilder.append(",").append(audioRecord.getMessage());
            });
            String result = stringBuilder.toString();
            //寻找电话号码
            Pattern pattern = Pattern.compile("\\d{5,}");
            Matcher matcher = pattern.matcher(result);
            while (matcher.find()) {
                audioKeyWords.getValues().get(AudioKeywordType.CONTACT_NUMBER.getType()).add(matcher.group());
            }
            //寻找其他类型关键字
            for (AudioKeywordType messageKeyword : AudioKeywordType.values()) {
                if (messageKeyword == AudioKeywordType.CONTACT_NUMBER) continue;
                for (String keyword : messageKeyword.getKeyword()) {
                    int keywordIndex = result.indexOf(keyword);
                    //问答式：截取关键字，从关键字的下一个[,/。]号开始截取到下下一个[,/。]号结束
                    if (keywordIndex != -1) {
                        int keyWordValueStartIndex = getKeyWordValueIndex(result, keywordIndex);
                        if (keyWordValueStartIndex == -1) continue;
                        int keyWordValueEndIndex = getKeyWordValueIndex(result, keyWordValueStartIndex);
                        if (keyWordValueEndIndex == -1) continue;
                        String keywordValue = result.substring(keyWordValueStartIndex, keyWordValueEndIndex);
                        if (StringUtils.isEmpty(keywordValue)) continue;
                        audioKeyWords.getValues().get(messageKeyword.getType()).add(keywordValue);
                    }
                }
            }
            ObjectMapper objectMapper = new ObjectMapper();
            byte[] bytes = objectMapper.writeValueAsString(audioKeyWords.getValues()).getBytes();
            emqKeeper.getMqttClient().publish(AudioTopic.KEYWORD.getName() + "/" + myNumber, bytes, 2, false);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("发送音频关键字消息异常，原因：" + e.getMessage());
        }
    }

    private int getKeyWordValueIndex(String text, int keywordIndex) {
        int keywordIndexNextFlag = -1;
        int keywordIndexNextFlag1 = text.indexOf(",", keywordIndex);
        int keywordIndexNextFlag2 = text.indexOf("。", keywordIndex);
        if (keywordIndexNextFlag1 != -1) {
            if (keywordIndexNextFlag2 != -1) {
                keywordIndexNextFlag = Math.min(keywordIndexNextFlag1, keywordIndexNextFlag2);
            } else {
                keywordIndexNextFlag = keywordIndexNextFlag1;
            }
        } else {
            if (keywordIndexNextFlag2 != -1) {
                keywordIndexNextFlag = keywordIndexNextFlag2;
            }
        }
        return keywordIndexNextFlag;
    }
}



