package com.cmvr.llm.util;

import com.alibaba.fastjson2.JSONObject;
import com.cmvr.llm.service.LLMAiTtsService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/**
 * LLM聊天服务 - 严格保持原接口参数
 */
@Slf4j
@Service
public class LlmChatService {
    @Autowired
    private LLMAiTtsService llmAiTtsService;
    private static final String DEFAULT_BASE_URL = "https://aiagentplatform.cmft.com/api/proxy/api/v1";
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final ObjectMapper objectMapper = new ObjectMapper();

    // 会话缓存：key = apiKey + "|" + apiId + "|" + userId
    private final ConcurrentHashMap<String, ConversationHolder> conversationCache = new ConcurrentHashMap<>();

    private final OkHttpClient httpClient;

    public LlmChatService() {
        this.httpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(120, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 核心方法：同步调用，返回完整字符串结果
     * 自动管理会话生命周期
     *
     * @param apiKey  对应原AppKey的header
     * @param apiId   对应原AppKey的body字段
     * @param userId  对应原UserID
     * @param body    请求体，必须包含Query字段，可选Name等
     * @return 完整AI回复字符串
     */
    public String chat(String apiKey, String apiId, String userId, Map<String, Object> body, boolean playTts, JSONObject ttsConfig) throws IOException {
        String cacheKey = apiKey + "|" + apiId + "|" + userId;

        // 获取或创建会话（严格保持原createConversation逻辑）
        ConversationHolder holder = conversationCache.computeIfAbsent(cacheKey, k -> {
            try {
                String conversationId = createConversation(apiKey, apiId, userId);
                System.out.println("创建新会话: " + conversationId);
                return new ConversationHolder(conversationId, apiKey, apiId, userId);
            } catch (IOException e) {
                throw new RuntimeException("创建会话失败", e);
            }
        });

        // 构建请求体 - 严格保持原buildChatRequestBody逻辑
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("AppKey", apiId);  // 对应原apiKey参数
        requestBody.put("AppConversationID", holder.conversationId);
        requestBody.put("UserID", userId);
        requestBody.put("ResponseMode", "streaming");
        requestBody.put("PubAgentJump", true);

        // 合并用户传入的body（包含Query等）
        if (body != null) {
            requestBody.putAll(body);
        }

        // 执行流式请求并同步返回完整结果
        return executeSseRequestSync(apiKey, requestBody, playTts, ttsConfig);
    }

    /**
     * 创建会话 - 完全保持原逻辑
     */
    private String createConversation(String apiKey, String apiId, String userId) throws IOException {
        Map<String, Object> body = new HashMap<>();
        body.put("AppKey", apiId);  // 对应原apiKey
        body.put("UserID", userId);
        // 如果调用方传了Name就用，否则自动生成
        if (!body.containsKey("Name")) {
            body.put("Name", "自动创建-" + System.currentTimeMillis());
        }

        String jsonBody = objectMapper.writeValueAsString(body);

        Request request = new Request.Builder()
                .url(DEFAULT_BASE_URL + "/create_conversation")
                .header("Apikey", apiKey)  // 对应原apiKey
                .header("Content-Type", "application/json")
                .post(RequestBody.create(jsonBody, JSON))
                .build();

        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("创建会话失败: " + response.code() + " - " + response.body().string());
            }

            String respJson = response.body().string();
            Map<String, Object> respMap = objectMapper.readValue(respJson, Map.class);
            Map<String, Object> conversation = (Map<String, Object>) respMap.get("Conversation");

            if (conversation == null) {
                throw new IOException("返回数据格式错误，缺少 Conversation 字段");
            }

            String conversationId = (String) conversation.get("AppConversationID");
            if (conversationId == null || conversationId.isEmpty()) {
                throw new IOException("返回数据格式错误，缺少 AppConversationID");
            }

            return conversationId;
        }
    }


    // 句子结束符号
    static final String SENTENCE_END = "?!。？！\n";
    /**
     * 执行SSE请求 - 完全保持原executeSseRequest逻辑，改为同步返回
     */
    private String executeSseRequestSync(String apiKey, Map<String, Object> requestBody, boolean playTts, JSONObject ttsConfig) throws IOException {
        String jsonBody = objectMapper.writeValueAsString(requestBody);

        Request request = new Request.Builder()
                .url(DEFAULT_BASE_URL + "/chat_query")
                .header("Apikey", apiKey)
                .header("Content-Type", "application/json")
                .header("Accept", "text/event-stream")
                .post(RequestBody.create(jsonBody, JSON))
                .build();

        StringBuilder fullContent = new StringBuilder();
        CountDownLatch mainLatch  = new CountDownLatch(1);
        AtomicReference<Throwable> errorRef = new AtomicReference<>();
        AtomicReference<String> finalMessageIdRef = new AtomicReference<>("");

        // ====================== 核心控制 ======================

        // 接收缓存：永远不阻塞
        StringBuilder receiveBuffer = new StringBuilder();
        // 单线程串行执行：保证上一句处理完才处理下一句
        ExecutorService sentenceExecutor = Executors.newSingleThreadExecutor();
        // 标记流是否已经结束
        AtomicBoolean streamFinished = new AtomicBoolean(false);
        final AtomicBoolean interrupted = new AtomicBoolean(false); // 中断标记
        Call call = httpClient.newCall(request);
        Runnable interruptTask = () -> {
            interrupted.set(true);
            call.cancel(); // 真正关闭SSE连接 【关键】
            streamFinished.set(true);
            sentenceExecutor.shutdownNow();
            mainLatch.countDown();
        };



        // 使用异步调用但阻塞等待结果
        call.enqueue(new Callback() {

            /**
             * 等待所有句子处理完再结束
             */
            private void shutdownAndWait1() {
                try {
                    sentenceExecutor.shutdown();
                    sentenceExecutor.awaitTermination(10, TimeUnit.MINUTES);
                } catch (InterruptedException ignored) {}
                mainLatch.countDown();
            }

            @Override
            public void onFailure(Call call, IOException e) {
                errorRef.set(e);
                streamFinished.set(true);
                shutdownAndWait1();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    String errorBody = response.body() != null ? response.body().string() : "无错误信息";
                    errorRef.set(new IOException("SSE请求失败: " + response.code() + " - " + errorBody));
                    streamFinished.set(true);
                    shutdownAndWait1();
                    return;
                }

                StringBuilder localContent = new StringBuilder();
                String finalMessageId = "";
                String currentEvent = "";

                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(response.body().byteStream(), StandardCharsets.UTF_8))) {

                    String line;
                    while (!interrupted.get() && (line = reader.readLine()) != null) {
                        if (line.isEmpty()) {
                            currentEvent = "";
                            continue;
                        }

                        if (line.startsWith("event:")) {
                            currentEvent = line.substring(6).trim();
                            continue;
                        }

                        if (line.startsWith("data:")) {
                            String data = line.substring(5).trim();

                            // 处理双重 data: 前缀（data:data: {...}）
                            if (data.startsWith("data:")) {
                                data = data.substring(5).trim();
                            }

                            if ("[DONE]".equals(data)) {
                                fullContent.append(localContent);
                                finalMessageIdRef.set(finalMessageId);
                                streamFinished.set(true);
                                processBufferIfNeed();
                                break;
                            }

                            try {
                                Map<String, Object> jsonData = objectMapper.readValue(data, Map.class);

                                String messageId = extractString(jsonData, "id", "task_id", "message_id");
                                if (!messageId.isEmpty()) {
                                    finalMessageId = messageId;
                                }

                                String event = (String) jsonData.getOrDefault("event", currentEvent);

                                if ("message".equals(event)) {
                                    String answer = extractString(jsonData, "answer", "content", "chunk", "text");
                                    if (!answer.isEmpty()) {
                                        localContent.append(answer);
                                        receiveBuffer.append(answer);
                                        processBufferIfNeed();
                                    }
                                } else if ("message_start".equals(event)) {
                                    log.info("消息开始，ID: " + finalMessageId);
                                } else if ("message_output_start".equals(event)) {
                                    log.info("输出开始");
                                } else if ("message_end".equals(event) || "end".equals(event)) {
                                    fullContent.append(localContent);
                                    finalMessageIdRef.set(finalMessageId);
                                    streamFinished.set(true);
                                    processBufferIfNeed();
                                    return;
                                }

                            } catch (Exception e) {
                                System.out.println("解析失败，原始数据: " + data);
                            }
                        }
                    }

                    // 流正常结束
                    fullContent.append(localContent);
                    finalMessageIdRef.set(finalMessageId);

                } catch (IOException e) {
                    errorRef.set(e);
                    streamFinished.set(true);
                } finally {
                    processBufferIfNeed();
                    shutdownAndWait1();
                }
            }

            /**
             * 核心：提取完整句子 + 异步串行处理
             */
            private void processBufferIfNeed() {
                if (interrupted.get()) return;
                if (!true) return;
                if (!playTts) return;

                sentenceExecutor.submit(() -> {
                    while (true) {
                        String buffer = receiveBuffer.toString();
                        // 寻找最后一个句子结束符
                        int lastSplit = -1;
                        for (int i = 0; i < buffer.length(); i++) {
                            if (SENTENCE_END.contains(String.valueOf(buffer.charAt(i)))) {
                                lastSplit = i;
                            }
                        }

                        // 有完整句子 或 流已结束
                        if (lastSplit >= 0 || streamFinished.get()) {
                            String sentence;
                            if (lastSplit >= 0) {
                                // 截取完整句子
                                sentence = buffer.substring(0, lastSplit + 1).trim();
                                // 保留剩余内容
                                String remain = buffer.substring(lastSplit + 1).trim();
                                receiveBuffer.setLength(0);
                                receiveBuffer.append(remain);
                            } else {
                                // 流结束，直接处理剩余
                                sentence = buffer.trim();
                                receiveBuffer.setLength(0);
                            }

                            if (!sentence.isEmpty()) {
                                if (interrupted.get()) return;
                                yourAsyncMethod(sentence, ttsConfig);
                            }

                            // 处理完继续循环，看是否还有新句子
                            if (streamFinished.get() && receiveBuffer.length() == 0) {
                                break;
                            }
                        } else {
                            // 无完整句子，退出
                            break;
                        }
                    }
                });
            }
        });

        // 等待流式传输完成
        try {
            boolean completed = mainLatch.await(120, TimeUnit.SECONDS);
            if (!completed) {
                throw new IOException("请求超时");
            }
        } catch (InterruptedException e) {
            interruptTask.run(); // 被中断时，立即停止SSE
            Thread.currentThread().interrupt();
            throw new IOException("请求被中断", e);
        }

        if (errorRef.get() != null) {
            if (errorRef.get() instanceof IOException) {
                throw (IOException) errorRef.get();
            } else {
                throw new IOException("请求异常", errorRef.get());
            }
        }

        return fullContent.toString();
    }

    private void yourAsyncMethod(String sentence, JSONObject ttsConfig) {
        try {
            log.info("正在处理句子: " + sentence);
            llmAiTtsService.play(ttsConfig.getString("url"), sentence, ttsConfig.getString("voice"), ttsConfig.getString("speed"), ttsConfig.getString("volume"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 完全保持原extractString方法
     */
    private String extractString(Map<String, Object> map, String... keys) {
        for (String key : keys) {
            Object value = map.get(key);
            if (value != null) {
                return value.toString();
            }
        }
        return "";
    }

    /**
     * Spring Boot停止时清理所有会话
     */
    @PreDestroy
    public void close() {
        System.out.println("开始清理会话，共 " + conversationCache.size() + " 个");

        conversationCache.values().forEach(holder -> {
            try {
                deleteConversation(holder);
                System.out.println("已删除会话: " + holder.conversationId);
            } catch (Exception e) {
                System.err.println("删除会话失败: " + holder.conversationId);
            }
        });

        conversationCache.clear();
        httpClient.dispatcher().executorService().shutdown();
        httpClient.connectionPool().evictAll();
        System.out.println("会话清理完成");
    }

    /**
     * 删除会话 - 完全保持原deleteConversation逻辑
     */
    private void deleteConversation(ConversationHolder holder) throws IOException {
        Map<String, Object> body = new HashMap<>();
        body.put("AppKey", holder.apiId);
        body.put("ConversationID", holder.conversationId);
        body.put("UserID", holder.userId);

        String jsonBody = objectMapper.writeValueAsString(body);

        Request request = new Request.Builder()
                .url(DEFAULT_BASE_URL + "/delete_conversation")
                .header("Apikey", holder.apiKey)
                .header("Content-Type", "application/json")
                .post(RequestBody.create(jsonBody, JSON))
                .build();

        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("删除会话失败: " + response.code());
            }
        }
    }

    /**
     * 内部会话持有类
     */
    private static class ConversationHolder {
        final String conversationId;
        final String apiKey;
        final String apiId;
        final String userId;

        ConversationHolder(String conversationId, String apiKey, String apiId, String userId) {
            this.conversationId = conversationId;
            this.apiKey = apiKey;
            this.apiId = apiId;
            this.userId = userId;
        }
    }
}