package cn.api.media.socket;

import cn.api.media.model.Message;
import cn.api.media.rpc.ApiUtils;
import cn.api.media.rpc.Wav;
import cn.api.media.utils.PcmCovWavUtil;
import cn.component.util.FileService;
import cn.hutool.core.io.IoUtil;
import cn.util.core.IsKit;
import cn.util.core.LogKit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Websocket 音频通讯
 */
@Component
@ServerEndpoint(value = "/atv/websocket/audio", configurator = WsConfigurator.class)
public class AudioController extends BaseMediaController {
    @Resource
    protected FileService fileService;

    private static final List<AbstractWsController> CONNECTIONS = new CopyOnWriteArrayList<>();

    /**
     * 创建等待队列
     * private static BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(50);
     * 创建一个单线执行任务，它可安排在给定延迟后运行命令或者定期地执行
     * corePoolSize -池中所保存的线程数，包括空闲线程
     * maximumPoolSize -池中允许的最大线程数
     * keepAliveTime -当线程数大于核心时，此为终止前多余的空闲线程等待新任务的最长时间
     * unit -keepAliveTime参数的时间单位
     * orkQueue -执行前用于保持任务的队列。此队列仅保持由execute方法提交的Runnable任务
     * private static ThreadPoolExecutor threadPoolExecutor =
     * new ThreadPoolExecutor(
     * 5, 100, 3
     * , TimeUnit.MILLISECONDS
     * , blockingQueue
     * , new NamedThreadFactory("thread", false)
     * , new ThreadPoolExecutor.CallerRunsPolicy());
     */
    private static ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    public void setThreadPoolTaskExecutor(ThreadPoolTaskExecutor threadPoolTaskExecutor) {
        AudioController.threadPoolTaskExecutor = threadPoolTaskExecutor;
    }

    /**
     * 并发容器 存储 字节临时缓冲区
     */
    private static ConcurrentHashMap<String, ByteArrayOutputStream> byteArrayOutputStreamConcurrentHashMap = new ConcurrentHashMap<>(30);

    /**
     * 并发容器 存储 转写结果容器
     */
    private static ConcurrentHashMap<String, StringBuffer> stringBufferConcurrentHashMap = new ConcurrentHashMap<>(30);
    @Override
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        System.out.println("Test---01");
        super.onOpen(session, config);
    }
    @Override
    @OnClose
    public void onClose() {
        System.out.println("Test---04");
        try {
            String userName = this.getUserName();
            stringBufferConcurrentHashMap.remove(userName);
            byteArrayOutputStreamConcurrentHashMap.remove(userName);
        } catch (Exception e) {
            LogKit.info(e.getMessage());
        }
        super.onClose();
    }
    @Override
    @OnMessage(maxMessageSize = 10000000)
    public void onMessage(String message) {
        System.out.println("Test---02："+message);
        super.onMessage(message);
    }

    @Override
    @OnMessage(maxMessageSize = 10000000)
    public void onMessage(ByteBuffer message) {
        // 为空时 不处理
        if (IsKit.isNullOrEmpty(message)) {
            return;
        }

        CompletableFuture.runAsync(() -> {
            String userName = this.getUserName();
            // 整体录音存储
            appendBuffer(message);
            // 休眠  防止过快
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                LogKit.info(e.getMessage());
            }

            // 临时 存储
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] bytes = message.array();
            try {
                byteArrayOutputStream.write(bytes);
            } catch (IOException e) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException ex) {
                    LogKit.info(ex.getMessage());
                }
                LogKit.info(e.getMessage());
                return;
            }

            // 内存处理 pcm转wav
            ByteArrayOutputStream pcmStream = new ByteArrayOutputStream();
            PcmCovWavUtil.convertWaveFile(byteArrayOutputStream, pcmStream);

            Wav waveFile = new Wav();
            waveFile.GetFromBytes(pcmStream.toByteArray());

            try {
                // 整体音频存储
                ByteArrayOutputStream stream = byteArrayOutputStreamConcurrentHashMap.get(userName);
                if (IsKit.isNotNullOrEmpty(stream)) {
                    ByteArrayOutputStream tempStream = new ByteArrayOutputStream();
                    PcmCovWavUtil.convertWaveFile(stream, tempStream);

                    /*Path path = Paths.get("").toAbsolutePath().resolve("tempAudio");
                    String filePath = path.toAbsolutePath().toString() + File.separator;
                    new File(filePath).mkdirs();*/

                    String filePath = fileService.getFileFullPath("audio");

                    FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath + userName + ".wav"));
                    IoUtil.copy(new ByteArrayInputStream(tempStream.toByteArray()), fileOutputStream);
                    fileOutputStream.flush();
                    fileOutputStream.close();
                }
            } catch (Exception e) {
                LogKit.info(e.getMessage());
            }

            String result = ApiUtils.sendToServer("qwertasd", waveFile.fs, waveFile.samples);
            StringBuffer stringBuffer = appendResult(result);
            // 转写结果 发送
            Message msg = new Message(getUserName(), Message.MsgConstant.MSG_TO_ALL, stringBuffer.toString());
            super.onMessage(msg.toString());

        }, threadPoolTaskExecutor);
    }

    /**
     * 并发容器 存储 字节临时缓冲区
     *
     * @param message ByteBuffer
     */
    private void appendBuffer(ByteBuffer message) {
        ByteArrayOutputStream byteArrayOutputStream = byteArrayOutputStreamConcurrentHashMap.get(this.getUserName());
        if (IsKit.isNullOrEmpty(byteArrayOutputStream)) {
            byteArrayOutputStream = new ByteArrayOutputStream();
        }

        byte[] bytes = message.array();
        try {
            byteArrayOutputStream.write(bytes);
        } catch (IOException e) {
            try {
                byteArrayOutputStream.close();
            } catch (IOException ex) {
                LogKit.info(ex.getMessage());
            }
            LogKit.info(e.getMessage());
            return;
        }

        byteArrayOutputStreamConcurrentHashMap.put(this.getUserName(), byteArrayOutputStream);
    }

    /**
     * 并发容器 存储 result
     *
     * @param result result
     * @return stringBuffer
     */
    private StringBuffer appendResult(String result) {

        StringBuffer stringBuffer = stringBufferConcurrentHashMap.get(this.getUserName());
        if (IsKit.isNullOrEmpty(stringBuffer)) {
            stringBuffer = new StringBuffer(this.getUserName() + ":");
        }
        if (IsKit.isNullOrEmpty(result)) {
            return stringBuffer;
        }
        if (stringBuffer.toString().length() > 30 && stringBuffer.toString().length() % 30 < 3) {
            stringBuffer.append("\n");
        }
        stringBuffer.append(result);
        stringBufferConcurrentHashMap.put(this.getUserName(), stringBuffer);
        return stringBuffer;
    }

    @Override
    @OnError
    public void onError(Throwable t) {
        try {
            String userName = this.getUserName();
            stringBufferConcurrentHashMap.remove(userName);

            byteArrayOutputStreamConcurrentHashMap.remove(userName);

        } catch (Exception e) {
            LogKit.info(e.getMessage());
        }
    }

    @Override
    List<AbstractWsController> getConnections() {
        return CONNECTIONS;
    }
    @Override
    String getConnectType() {
        return "audio";
   }
}
