package org.dromara.talk.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.talk.domain.bo.PhoneUserBo;
import org.dromara.talk.domain.bo.TalkAgentBo;
import org.dromara.talk.domain.bo.TalkSessionBo;
import org.dromara.talk.domain.dto.MessageStreamRequest;
import org.dromara.talk.domain.vo.TalkAgentVo;
import org.dromara.talk.domain.vo.TalkSessionVo;
import org.dromara.talk.service.IChatService;
import org.dromara.talk.service.IDifyService;
import org.dromara.talk.service.IPhoneUserService;
import org.dromara.talk.service.ITalkAgentService;
import org.dromara.talk.service.ITalkSessionService;
import org.dromara.talk.service.ITtsService;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
@Service
public class ChatServiceImpl implements IChatService {

    private final ITtsService ttsService;
    private final ITalkAgentService talkAgentService;
    private final IDifyService difyService;
    private final ITalkSessionService talkSessionService;
    private final IPhoneUserService phoneUserService;

    // 存储每个用户的最新请求ID
    private final Map<Long, Integer> latestRequestIdMap = new ConcurrentHashMap<>();

    // 存储每个会话的对话内容
    private final Map<String, List<Map<String, String>>> conversationMap = new ConcurrentHashMap<>();

    /**
     * 合成音频并通过 SSE 发送
     *
     * @param text 要合成的文本
     * @param agentConfig 客服配置
     * @param emitter SSE 发送器
     */
    private void synthesizeAndSendAudio(String text, TalkAgentVo agentConfig, SseEmitter emitter) {
        CountDownLatch latch = new CountDownLatch(1);
        ByteArrayOutputStream mergedAudioBytes = new ByteArrayOutputStream();

        ttsService.synthesizeStream(text, agentConfig, (audioChunk, status) -> {
            try {
                byte[] audioBytes = Base64.getDecoder().decode(audioChunk);
                mergedAudioBytes.write(audioBytes);

                if (status == 2) {
                    String mergedAudioBase64 = Base64.getEncoder().encodeToString(mergedAudioBytes.toByteArray());
                    Map<String, String> audioEvent = new HashMap<>();
                    audioEvent.put("name", "audio");
                    audioEvent.put("data", mergedAudioBase64);
                    emitter.send(SseEmitter.event().data(audioEvent));
                    latch.countDown();
                }
            } catch (Exception e) {
                log.error("发送音频失败", e);
                latch.countDown();
            }
        });

        try {
            latch.await(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error("等待音频合成被中断", e);
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public void processMessageStream(MessageStreamRequest request, SseEmitter emitter) {
        // 在主线程中获取用户ID，避免在异步线程中访问ThreadLocal
        Long userId = LoginHelper.getUserId();
        if (userId == null) {
            userId = 0L;
            log.warn("获取登录用户ID失败，使用默认值");
        }

        // 更新最新请求ID
        if (request.getRequestId() != null) {
            latestRequestIdMap.put(userId, request.getRequestId());
            log.info("流式请求 - 更新用户 {} 的最新请求ID为: {}", userId, request.getRequestId());
        }

        Long finalUserId = userId;
        CompletableFuture.runAsync(() -> {
            try {

                // 获取客服配置
                TalkAgentVo agentConfig = null;
                if (request.getAgentId() != null) {
                    agentConfig = talkAgentService.queryById(request.getAgentId());
                }

                // 如果是欢迎语，合成语音但不发送text事件（避免前端重复显示）
                if (Boolean.TRUE.equals(request.getIsGreeting())) {
                    // 合成欢迎语语音
                    synthesizeAndSendAudio(request.getMessage(), agentConfig, emitter);

                    // 发送完成信号
                    Map<String, String> doneEvent = new HashMap<>();
                    doneEvent.put("name", "done");
                    doneEvent.put("data", "");
                    emitter.send(SseEmitter.event()
                        .data(doneEvent));
                    emitter.complete();
                    return;
                }

                TalkAgentVo finalAgentConfig = agentConfig;
                Integer finalRequestId = request.getRequestId();

                // 初始化对话记录列表
                String finalConversationId = request.getConversationId();
                if (finalConversationId != null) {
                    // 使用 computeIfAbsent 避免竞态条件
                    conversationMap.computeIfAbsent(finalConversationId, k -> new ArrayList<>());

                    // 添加用户消息（客户）
                    Map<String, String> userMsg = new HashMap<>();
                    userMsg.put("role", "user");
                    userMsg.put("content", request.getMessage());
                    userMsg.put("timestamp", String.valueOf(System.currentTimeMillis()));
                    conversationMap.get(finalConversationId).add(userMsg);
                }

                // 用于累积AI回复的完整文本
                StringBuilder aiReplyBuilder = new StringBuilder();

                // 检查 conversationId 是否是临时 sessionId
                // 如果是临时 sessionId（数据库中还未被 Dify 更新），则传递 null 给 Dify
                String difyConversationId = request.getConversationId();
                if (request.getConversationId() != null) {
                    TalkSessionVo session = talkSessionService.queryBySessionId(request.getConversationId());
                    if (session != null && request.getConversationId().equals(session.getSessionId())) {
                        // 检查这个 sessionId 是否是刚创建的（没有对话内容）
                        // 如果没有对话内容，说明这是第一次对话，不应该传递给 Dify
                        if (session.getConversationJson() == null || session.getConversationJson().isEmpty()) {
                            difyConversationId = null;
                            log.info("检测到临时 sessionId，第一次对话不传递 conversationId 给 Dify");
                        }
                    }
                }

                difyService.callWorkflowStream(request.getMessage(), request.getAgentGender(), request.getTtsVcnList(), agentConfig, finalUserId, difyConversationId, request.getCustomerPhone(), request.getType(),
                    (textChunk) -> {
                        try {
                            // 累积AI回复文本
                            aiReplyBuilder.append(textChunk);

                            // 构建 JSON 格式的事件数据
                            Map<String, String> eventData = new HashMap<>();
                            eventData.put("name", "text");
                            eventData.put("data", textChunk);
                            emitter.send(SseEmitter.event()
                                .data(eventData));
                        } catch (Exception e) {
                            log.error("发送文本失败", e);
                        }
                    },
                    (sentence, newConversationId, isComplete) -> {
                        try {
                            log.info("句子回调 - 句子: {}, isComplete: {}", sentence != null ? sentence : "(null)", isComplete);

                            // 发送conversationId
                            if (newConversationId != null) {
                                // 使用 computeIfAbsent 确保线程安全
                                conversationMap.computeIfAbsent(newConversationId, k -> new ArrayList<>());

                                // 更新conversationId
                                if (finalConversationId == null) {
                                    // 第一次对话，已经在上面创建了列表
                                } else if (!finalConversationId.equals(newConversationId)) {
                                    // 如果传入的conversationId与Dify返回的不同,说明传入的是临时sessionId
                                    // 需要更新数据库中的sessionId
                                    talkSessionService.updateSessionId(finalConversationId, newConversationId);
                                    log.info("更新临时sessionId {} 为Dify的conversationId {}", finalConversationId, newConversationId);
                                }

                                // 添加用户消息（客户）- 每次对话都要添加
                                Map<String, String> userMsg = new HashMap<>();
                                userMsg.put("role", "user");
                                userMsg.put("content", request.getMessage());
                                userMsg.put("timestamp", String.valueOf(System.currentTimeMillis()));
                                conversationMap.get(newConversationId).add(userMsg);

                                Map<String, String> conversationEvent = new HashMap<>();
                                conversationEvent.put("name", "conversationId");
                                conversationEvent.put("data", newConversationId);
                                emitter.send(SseEmitter.event()
                                    .data(conversationEvent));
                            }

                            // 检查是否需要合成音频（只为最新请求合成音频）
                            boolean needAudio = true;
                            if (finalRequestId != null) {
                                Integer latestRequestId = latestRequestIdMap.get(finalUserId);
                                if (latestRequestId != null && !latestRequestId.equals(finalRequestId)) {
                                    needAudio = false;
                                    log.info("流式请求ID {} 不是最新请求（最新为 {}），跳过音频合成", finalRequestId, latestRequestId);
                                }
                            }

                            if (needAudio && sentence != null && !sentence.trim().isEmpty()) {
                                log.info("合成句子音频，长度: {}, 内容: {}", sentence.length(), sentence);
                                synthesizeAndSendAudio(sentence, finalAgentConfig, emitter);
                            }

                            // 如果是最后一个句子，发送完成事件
                            if (isComplete) {
                                log.info("收到完成标志，准备发送done事件");

                                // 保存对话内容到数据库
                                if (newConversationId != null && finalAgentConfig != null) {
                                    try {
                                        // 获取当前会话的对话内容
                                        List<Map<String, String>> messages = conversationMap.getOrDefault(newConversationId, new ArrayList<>());

                                        // 添加AI回复消息（客服）
                                        if (aiReplyBuilder.length() > 0) {
                                            Map<String, String> assistantMsg = new HashMap<>();
                                            assistantMsg.put("role", "assistant");
                                            assistantMsg.put("content", aiReplyBuilder.toString());
                                            assistantMsg.put("timestamp", String.valueOf(System.currentTimeMillis()));
                                            messages.add(assistantMsg);
                                        }

                                        // 将对话内容转换为JSON字符串
                                        String conversationJson = new ObjectMapper().writeValueAsString(messages);

                                        // 保存到数据库
                                        talkSessionService.saveOrUpdateConversation(newConversationId, finalAgentConfig.getId(), conversationJson, null, finalUserId);

                                        log.info("对话内容已保存到数据库，会话ID: {}, 消息数量: {}", newConversationId, messages.size());

                                        // 清理内存：对话完成后从 conversationMap 中移除
                                        conversationMap.remove(newConversationId);
                                        log.debug("已清理会话 {} 的对话内容缓存", newConversationId);
                                    } catch (Exception e) {
                                        log.error("保存对话内容失败", e);
                                    }
                                }

                                Map<String, String> doneEvent = new HashMap<>();
                                doneEvent.put("name", "done");
                                doneEvent.put("data", "");
                                emitter.send(SseEmitter.event()
                                    .data(doneEvent));
                                log.info("done事件已发送，关闭SSE连接");
                                emitter.complete();
                            }
                        } catch (Exception e) {
                            log.error("处理句子回调失败", e);
                            emitter.completeWithError(e);
                        }
                    });

            } catch (Exception e) {
                log.error("流式处理失败", e);
                try {
                    emitter.completeWithError(e);
                } catch (Exception ex) {
                    log.error("发送错误失败", ex);
                }
            }
        });
    }

    @Override
    public Map<String, Object> startChatSession(Long agentId, Long userId, String customerPhone) {
        boolean success = talkAgentService.changeAgentStatus(agentId, "2");
        if (!success) {
            log.warn("客服 {} 开始对话失败，可能已被占用", agentId);
            return Map.of("success", false, "code", 400, "msg", "该客服已被其他用户占用，请选择其他客服");
        }

        String tempSessionId = UUID.randomUUID().toString();

        // 如果有客户电话，检查并保存到 phone_user 表
        if (customerPhone != null && !customerPhone.isEmpty()) {
            try {
                PhoneUserBo phoneUserBo = new PhoneUserBo();
                phoneUserBo.setCustomerPhone(customerPhone);
                phoneUserService.insertByBo(phoneUserBo);
                log.info("新客户电话已保存: {}", customerPhone);
            } catch (Exception e) {
                log.debug("客户电话可能已存在: {}", customerPhone);
            }
        }

        TalkSessionBo sessionBo = new TalkSessionBo();
        sessionBo.setSessionId(tempSessionId);
        sessionBo.setAgentId(agentId);
        sessionBo.setStartTime(new Date());
        sessionBo.setUserId(userId);
        if (customerPhone != null) {
            sessionBo.setCustomerPhone(customerPhone);
        }
        talkSessionService.insertByBo(sessionBo);

        log.info("客服 {} 开始对话，sessionId: {}, customerPhone: {}, 创建人: {}", agentId, tempSessionId, customerPhone, userId);
        return Map.of("success", true, "code", 200, "sessionId", tempSessionId);
    }

    @Override
    public Boolean hangupCall(Long agentId, String sessionId, List<Map<String, Object>> chatHistory) {
        // 更新会话结束时间并保存对话内容
        if (sessionId != null) {
            talkSessionService.updateEndTime(sessionId);

            // 保存对话内容
            if (chatHistory != null && !chatHistory.isEmpty()) {
                try {
                    // 转换前端格式到后端格式
                    List<Map<String, String>> messages = new ArrayList<>();
                    for (Map<String, Object> msg : chatHistory) {
                        Map<String, String> message = new HashMap<>();
                        String type = (String) msg.get("type");
                        String content = (String) msg.get("content");

                        // 转换 type: user/agent 到 role: user/assistant
                        message.put("role", "user".equals(type) ? "user" : "assistant");
                        message.put("content", content);
                        message.put("timestamp", String.valueOf(System.currentTimeMillis()));
                        messages.add(message);
                    }

                    String conversationJson = new ObjectMapper().writeValueAsString(messages);
                    talkSessionService.saveOrUpdateConversation(sessionId, agentId, conversationJson, null, null);
                    log.info("挂断时保存对话内容，会话ID: {}, 消息数量: {}", sessionId, messages.size());
                } catch (Exception e) {
                    log.error("保存对话内容失败", e);
                }
            }
        }

        // 将客服状态改为空闲
        TalkAgentBo bo = new TalkAgentBo();
        bo.setId(agentId);
        bo.setStatus("0");
        boolean success = talkAgentService.updateByBo(bo);
        log.info("客服 {} 挂断电话，状态已改为空闲中，会话ID: {}", agentId, sessionId);
        return success;
    }
}
