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

import com.yeejoin.amos.boot.module.jcs.biz.audioToText.AudioKeyWord;
import com.yeejoin.amos.boot.module.jcs.biz.audioToText.AudioRecord;
import com.yeejoin.amos.boot.module.jcs.biz.audioToText.RealTimeSpeechTranscriberListener;
import com.yeejoin.amos.speech.AppSpeechTranscriber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.typroject.tyboot.component.emq.EmqKeeper;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 实时语音转文字
 */
@Component
public class RealTimeStream2Text {
    private static final Logger logger = LoggerFactory.getLogger(RealTimeStream2Text.class);
    public static int serverPort = 10001;

    @Autowired
    private EmqKeeper emqKeeper;

    /**
     * 开始语音转文字
     *
     * @param myNumber     我的电话号码
     * @param callerNumber 呼入电话号码
     */
    public HashMap<String, Object> doTranslate(String cid, String myNumber, String callerNumber) {
        //启动两个监听端口监听推送进来的2路语音流
        ServerSocket serverSocket1 = initServerSocketPort();
        ServerSocket serverSocket2 = initServerSocketPort();
        //识别的记录
        List<AudioRecord> audioRecords = new ArrayList<>();
        //识别的关键字
        AudioKeyWord audioKeyWord = new AudioKeyWord();
        logger.warn("myNumber监听的端口为：" + serverSocket1.getLocalPort() + "  callerNumber监听的端口为：" + serverSocket2.getLocalPort());
        //我的语音流
        Thread thread1 = new Thread(() -> {
            new AppSpeechTranscriber(new RealTimeSpeechTranscriberListener(myNumber, myNumber, emqKeeper, audioRecords, audioKeyWord), serverSocket1).process();
        });
        //呼入的语音流
        Thread thread2 = new Thread(() -> {
            new AppSpeechTranscriber(new RealTimeSpeechTranscriberListener(myNumber, callerNumber, emqKeeper, audioRecords, audioKeyWord), serverSocket2).process();
        });
        thread1.setUncaughtExceptionHandler(new SubUncaughtExceptionHandler(serverSocket1));
        thread2.setUncaughtExceptionHandler(new SubUncaughtExceptionHandler(serverSocket2));
        thread1.start();
        thread2.start();
        HashMap<String, Object> map = new HashMap<>();
        map.put(myNumber, serverSocket1.getLocalPort());
        map.put(callerNumber, serverSocket2.getLocalPort());
        return map;
    }

    /**
     * 获取一个ServerSocket端口号
     */
    private ServerSocket initServerSocketPort() {
        while (true) {
            try {
                return new ServerSocket(serverPort);
            } catch (IOException exception) {
                serverPort++;
                if (serverPort == 65535) serverPort = 10000;
            }
        }
    }

    /**
     * 线程抛出异常，关闭监听端口，防止端口未安全关闭
     */
    static class SubUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
        private static final Logger logger = LoggerFactory.getLogger(SubUncaughtExceptionHandler.class);
        ServerSocket serverSocket;

        public SubUncaughtExceptionHandler(ServerSocket serverSocket) {
            this.serverSocket = serverSocket;
        }

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            if (serverSocket != null && !serverSocket.isClosed()) {
                try {
                    serverSocket.close();
                    logger.error("子线程出现异常，已关闭音频监听端口。" + e.getMessage());
                } catch (IOException exception) {
                    exception.printStackTrace();
                }
            }
        }
    }
}
