package com.vetti.common.ai.elevenLabs;

import cn.hutool.json.JSONUtil;
import com.google.gson.Gson;
import com.vetti.common.ai.elevenLabs.vo.VoiceSettings;
import com.vetti.common.ai.elevenLabs.vo.VoicesResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.websocket.Session;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

/**
 * 文本转换为语音
 */
@Slf4j
@Component
public class ElevenLabsStreamClient {

    @Value("${elevenLabs.baseUrl}")
    private String BASE_URL;

    @Value("${elevenLabs.apiKey}")
    private String apiKey;

    @Value("${elevenLabs.modelId}")
    private String modelId;


    /**
     * 将文本转换为语音并保存到文件
     *
     * @param text           要转换的文本
     * @param voiceId        语音ID (可从ElevenLabs网站获取)
     * @throws IOException 网络请求或文件操作异常
     */
    private void textToSpeech(String text, String voiceId, CloseableHttpClient httpClient, Session session,String outputFormat) throws IOException {
        HttpPost httpPost = new HttpPost(BASE_URL + "/text-to-speech/" + voiceId+"/stream?output_format="+outputFormat);
        httpPost.setHeader("xi-api-key", apiKey);
        httpPost.setHeader("Content-Type", "application/json");

        Map<String, Object> payload = new HashMap<>();
        payload.put("text", text);
        payload.put("model_id", modelId);
        payload.put("voice_settings", new VoiceSettings(0.85, 0.5,0.1,0,0.9,1));
        Gson gson = new Gson();
        StringEntity entity = new StringEntity(gson.toJson(payload), ContentType.APPLICATION_JSON);
        httpPost.setEntity(entity);
        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            HttpEntity responseEntity = response.getEntity();
            if (responseEntity != null) {
                try (InputStream inputStream = responseEntity.getContent();) {
                    // 锁（数组是为了内部类可写）
                    boolean[] sending = new boolean[]{false};
                    //用来合并零散的碎片
                    ByteArrayOutputStream smallChunkBuffer = new ByteArrayOutputStream();
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    log.info("开始发送语音流:{}",System.currentTimeMillis()/1000);
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        try{
                            // 如果上一包还在发送 → 阻塞等待
                            while (sending[0]) {
                                // 轻量等待，不耗 CPU
                                Thread.sleep(1);
                            }
                        }catch (Exception e){}
                        //语音流合并到2KB左右进行发送
                        if(smallChunkBuffer.size() >= 4096){
                            // 🔥开始发送 → 上锁
                            sending[0] = true;
//                            log.info("语音流大于"+smallChunkBuffer.size()+"啦,发送完成!!!");
                            byte[] merged = smallChunkBuffer.toByteArray();
                            smallChunkBuffer.reset();
                            session.getAsyncRemote().sendBinary(ByteBuffer.wrap(merged), result -> {
                                if (!result.isOK()) {
                                    log.info("发送失败: " + result.getException());
                                }
                                // 🔥发送完毕 → 解锁
                                sending[0] = false;
                            });
                        }
                        // 零散的碎片 → 加入缓冲区，不立即发送
                        smallChunkBuffer.write(buffer, 0, bytesRead);
                    }
                    //都加完缓冲区,最最后一次发送
                    if(smallChunkBuffer.size() > 2){
                        try {
                            Thread.sleep(50);
                        }catch (Exception e){}
                        // 如果上一包还在发送 → 阻塞等待
                        byte[] merged = smallChunkBuffer.toByteArray();
                        smallChunkBuffer.reset();
                        session.getAsyncRemote().sendBinary(ByteBuffer.wrap(merged), result -> {
                        });
                    }
                    log.info("结束发送语音流:{}",System.currentTimeMillis()/1000);
                    //返回结束点
                    try {
                        Thread.sleep(50);
                    }catch (Exception e){}
                    Map<String,String> dataText = new HashMap<>();
                    dataText.put("type","voiceEnd");
                    dataText.put("content","");
                    session.getBasicRemote().sendText(JSONUtil.toJsonStr(dataText));
                }
            }
        }
    }

    /**
     * 获取可用的语音列表
     *
     * @return 语音列表响应
     * @throws IOException 网络请求异常
     */
    private VoicesResponse getVoices(CloseableHttpClient httpClient){
        HttpGet httpGet = new HttpGet(BASE_URL + "/voices");
        httpGet.setHeader("xi-api-key", apiKey);
        Gson gson = new Gson();
        try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
            HttpEntity responseEntity = response.getEntity();
            String responseBody = EntityUtils.toString(responseEntity);
            return gson.fromJson(responseBody, VoicesResponse.class);
        }catch (Exception e){
            throw new RuntimeException("获取可用的语音列表异常");
        }
    }

    /**
     * 处理文本转换成语音文件
     * @param inputText
     * @return
     */
    public void handleTextToVoice(String inputText,Session session,String outputFormat){
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            // 使用第一个可用语音进行文本转语音(澳洲本地女声)
//            String firstVoiceId = "56bWURjYFHyYyVf490Dp";
            String firstVoiceId = "56bWURjYFHyYyVf490Dp";
            textToSpeech(inputText, firstVoiceId,httpClient,session,outputFormat);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendAudioStream(Session session, InputStream inputStream) throws IOException {
        byte[] buffer = new byte[2048];  // 分片大小，可调
        final int[] bytesReadHolder = new int[1];
        // 定义一个递归任务
        final Runnable[] sender = new Runnable[1];
        sender[0] = () -> {
            try {
                bytesReadHolder[0] = inputStream.read(buffer);
                // 结束条件
                if (bytesReadHolder[0] == -1) {
                    log.info("音频流发送完毕");
                    Map<String,String> dataText = new HashMap<>();
                    dataText.put("type","voiceEnd");
                    dataText.put("content","");
                    session.getBasicRemote().sendText(JSONUtil.toJsonStr(dataText));
                    return;
                }
                ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, bytesReadHolder[0]);
                session.getAsyncRemote().sendBinary(byteBuffer, result -> {
                    if (result.isOK()) {
                        log.info("正常语音发送出去语音流啦!!! 大小={} 字节", bytesReadHolder[0]);
                        // 当前块发送成功，继续发送下一块
                        sender[0].run();
                    } else {
                        log.error("发送失败: {}", result.getException().getMessage());
                    }
                });
            } catch (IOException e) {
                log.error("流读取错误: {}", e.getMessage());
            }
        };
        // 启动递归链
        sender[0].run();
    }

}
