package cn.com.poc.expose.websocket.handler;

import cn.com.poc.common.service.BosConfigService;
import cn.com.poc.common.utils.*;
import cn.com.poc.expose.websocket.dto.TextToSpeechTencentResponse;
import cn.com.poc.expose.websocket.exception.WebsocketException;
import cn.com.yict.framemax.core.config.Config;
import cn.com.yict.framemax.core.exception.BusinessException;
import cn.com.yict.framemax.core.i18n.I18nUtils;
import com.tencent.SpeechClient;
import com.tencent.tts.model.SpeechSynthesisRequest;
import com.tencent.tts.model.SpeechSynthesisResponse;
import com.tencent.tts.service.SpeechSynthesisListener;
import com.tencent.tts.service.SpeechSynthesizer;
import org.java_websocket.WebSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class TextToSpeechTencentHandler extends AbstractWsHandler {

    final Logger logger = LoggerFactory.getLogger(TextToSpeechTencentHandler.class);

    private SpeechSynthesizer speechSynthesizer;

    private BosConfigService bosConfigService;

    @Override
    public void doHandler(WebSocket webSocket, String message) {
        try {
            bosConfigService = SpringUtils.getBean(BosConfigService.class);
            TextToSpeechTencentResponse response = JsonUtils.deSerialize(message, TextToSpeechTencentResponse.class);
            if (response == null) {
                throw new WebsocketException("arg cannot null");
            }
            if (StringUtils.isBlank(response.getContent())) {
                throw new WebsocketException("content cannot null");
            }
            initTTS(webSocket, response);
            textToSpeech(response.getContent());
        } catch (Exception e) {
            WebsocketException websocketException = new WebsocketException(e);
            webSocket.send(websocketException.getMessage());
            throw websocketException;
        }
    }

    /**
     * 调用TTS
     */
    private void textToSpeech(String text) {
        this.speechSynthesizer.synthesisLongText(text);
    }


    /**
     * 初始化TTS
     */
    private void initTTS(WebSocket webSocket, TextToSpeechTencentResponse textToSpeechTencentResponse) throws IOException {
        //从配置文件读取密钥
        String appId = Config.get("tencent.speech.synthesizer.appid");
        String secretId = Config.get("tencent.speech.synthesizer.secretId");
        String secretKey = Config.get("tencent.speech.synthesizer.secretKey");
        //创建SpeechSynthesizerClient实例，目前是单例
        SpeechClient client = SpeechClient.newInstance(appId, secretId, secretKey);
        //初始化SpeechSynthesizerRequest，SpeechSynthesizerRequest包含请求参数
        SpeechSynthesisRequest request = SpeechSynthesisRequest.initialize();
        request.setSampleRate(textToSpeechTencentResponse.getSampleRate());
        request.setSpeed(textToSpeechTencentResponse.getSpeed());
        request.setCodec(textToSpeechTencentResponse.getCodec());
        request.setVolume(textToSpeechTencentResponse.getVolume());
        request.setVoiceType(textToSpeechTencentResponse.getVoiceType());
        //使用客户端client创建语音合成实例

        if ("wav".equals(textToSpeechTencentResponse.getCodec())) {
            request.setCodec("pcm");
        }


        speechSynthesizer = client.newSpeechSynthesizer(request, new SpeechSynthesisListener() {
            List<byte[]> audioBytes = new ArrayList<>();

            AtomicInteger sessionId = new AtomicInteger(0);
            File tempAudioFile = File.createTempFile(UUIDTool.getUUID(), textToSpeechTencentResponse.getCodec());

            AtomicInteger count = new AtomicInteger(0);

            @Override
            public void onComplete(SpeechSynthesisResponse response) {
                logger.info("onComplete");
                try (FileOutputStream fileOutputStream = new FileOutputStream(tempAudioFile, true)) {
                    for (byte[] audioByte : audioBytes) {
                        fileOutputStream.write(audioByte);
                    }
                } catch (IOException e) {
                    logger.error("onComplete:{}", e.getMessage());
                }

                Path path = tempAudioFile.toPath();
                if ("wav".equals(textToSpeechTencentResponse.getCodec())) {
                    try {
                        path = PcmToWav.convertAudioFiles(tempAudioFile.getPath());
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }

                //上传音频
                try (InputStream fileInputStream = Files.newInputStream(path);) {
                    String uploadUrl = bosConfigService.upload(fileInputStream, textToSpeechTencentResponse.getCodec(), null);
                    webSocket.send("{\"replyVoiceUrl\":\"" + uploadUrl + "\"}");
                } catch (Exception e) {
                    throw new BusinessException(e);
                }
                webSocket.send("{\"final\":true}");
                webSocket.close();
            }

            @Override
            public void onMessage(byte[] data) {
                //发送音频
                sessionId.incrementAndGet();
                Base64.Encoder encoder = Base64.getEncoder();
                String base64 = encoder.encodeToString(data);
                webSocket.send("{\"sessionId\":" + count.get() + ",\"audio\":\"" + base64 + "\"}");
                audioBytes.add(data);
            }

            @Override
            public void onFail(SpeechSynthesisResponse response) {
                logger.warn("onFail:{}", response.getMessage());
                WebsocketException websocketException = new WebsocketException(response.getMessage());
                webSocket.send(websocketException.toString());
                webSocket.close();
                throw websocketException;
            }

        });
    }
}
