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;
    private final ObjectMapper objectMapper = new ObjectMapper();

    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("服务端准备好了进行识别");
    }

    /**
     * 服务端检测到了一句话的开始
     */
    @Override
    public void onSentenceBegin(SpeechTranscriberResponse response) {
        logger.warn("服务端检测到了一句话的开始");
    }

    /**
     * 服务端检测到了一句话的结束
     * 识别出一句话。服务端会智能断句，当识别到一句话结束时会返回此消息。
     */
    @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()));
            Pattern pattern = Pattern.compile("\\d{5,}");
            Matcher matcher = pattern.matcher(stringBuilder.toString());
            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()) {
                    for (int i = 0; i < audioRecords.size(); i++) {
                        String message = audioRecords.get(i).getMessage();
                        String nextMessage = "";
                        if (i + 1 < audioRecords.size()) {
                            nextMessage = audioRecords.get(i + 1).getMessage();
                        }
                        int keywordIndex = message.indexOf(keyword);
                        if (keywordIndex != -1) {
                            try {
                                // 第一种(获取keyword紧跟的内容直至结束)
                                String keywordValue = message.substring(keywordIndex + keyword.length());
                                if (!StringUtils.isEmpty(keywordValue) && keywordValue.length() > 2) {
                                    audioKeyWords.getValues().get(messageKeyword.getType()).add(keywordValue);
                                }
                                // 第二种(获取keyword的下一句话直至结束)
                                if (!StringUtils.isEmpty(nextMessage)) {
                                    audioKeyWords.getValues().get(messageKeyword.getType()).add(nextMessage);
                                }
                            } catch (Exception e) {
                                logger.error(e.getMessage());
                            }
                        }
                    }
                }
            }
            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());
        }
    }
}



