package org.xyzh.ai.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;

import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.xyzh.ai.client.DifyApiClient;
import org.xyzh.ai.client.callback.StreamCallback;
import org.xyzh.ai.client.dto.ChatRequest;
import org.xyzh.ai.config.DifyConfig;
import org.xyzh.ai.mapper.TbChatMapper;
import org.xyzh.ai.mapper.TbChatMessageMapper;
import org.xyzh.api.ai.dto.ChatPrepareData;
import org.xyzh.api.ai.dto.DifyFileInfo;
import org.xyzh.api.ai.dto.TbAgent;
import org.xyzh.api.ai.dto.TbChat;
import org.xyzh.api.ai.dto.TbChatMessage;
import org.xyzh.api.ai.dto.TbKnowledge;
import org.xyzh.api.ai.service.AgentChatService;
import org.xyzh.api.ai.service.AgentService;
import org.xyzh.api.ai.service.KnowledgeService;
import org.xyzh.api.system.service.GuestService;
import org.xyzh.common.core.domain.LoginDomain;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.common.utils.NonUtils;
import org.xyzh.common.utils.id.IdUtil;
import org.xyzh.common.auth.utils.LoginUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @description 智能体对话服务实现
 * @filename AgentChatServiceImpl.java
 * @author yslg
 * @copyright xyzh
 * @since 2025-12-17
 */
@DubboService(
    version = "1.0.0",
    group = "ai",
    timeout = 3000,
    retries = 0
)
public class AgentChatServiceImpl implements AgentChatService {
    private static final Logger logger = LoggerFactory.getLogger(AgentChatServiceImpl.class);

    private static final String CHAT_SESSION_PREFIX = "ai:chat:session:";
    private static final long SESSION_TTL = 5 * 60;

    @Autowired
    private TbChatMapper chatMapper;

    @Autowired
    private TbChatMessageMapper chatMessageMapper;

    @Autowired
    private AgentService agentService;

    @Autowired
    private DifyApiClient difyApiClient;

    @Autowired
    private RedisService redisService;

    @Autowired
    private KnowledgeService knowledgeService;

    @Autowired
    private DifyConfig difyConfig;

    /**
     * @description 判断智能体是否是outer
     * @param agentId 智能体ID
     * @return true-是outer，false-不是outer
     */
    private Boolean isOuterAgent(String agentId){
        // 智能体必须是outer
        ResultDomain<TbAgent> agentResult = agentService.selectAgentById(agentId);
        if(!agentResult.getSuccess()|| agentResult.getData() == null || !agentResult.getData().getIsOuter()){
            return false;
        }
        return true;
    }

    // ====================== 智能体会话管理 ======================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbChat> createChat(TbChat chat) {
        // 如果是来客（userType=false），校验智能体是否是 isOuter
        if(!chat.getUserType()){
            if(!isOuterAgent(chat.getAgentId())){
                return ResultDomain.failure("智能体不可用");
            }
        }
        // 设置chat（来客传入的 userId 已经是真正的系统 userId）
        chat.setOptsn(IdUtil.getOptsn());
        chat.setChatId(IdUtil.generateID());
        chatMapper.insertChat(chat);
        return ResultDomain.success("创建成功", chat);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbChat> updateChat(TbChat chat) {
        // 1. 校验会话
        TbChat chat2 = chatMapper.selectChatById(chat.getChatId());
        if (chat2 == null) {
            return ResultDomain.failure("会话不存在");
        }
        // 判断agent是否是outer
        if(!isOuterAgent(chat.getAgentId())){
            return ResultDomain.failure("智能体不可用");
        }

        // 2. 获取用户ID并校验权限
        LoginDomain loginDomain = LoginUtil.getCurrentLogin();
        String userId = loginDomain.getUser().getUserId();
        if (userId == null) {
            return ResultDomain.failure("用户信息获取失败");
        }
        if (!chat2.getUserId().equals(userId)) {
            return ResultDomain.failure("无权修改此会话");
        }

        // 3. 更新会话
        TbChat update = new TbChat();
        update.setChatId(chat.getChatId());
        update.setTitle(chat.getTitle());

        int rows = chatMapper.updateChat(update);
        if (rows > 0) {
            return ResultDomain.success("更新会话成功", update);
        }

        return ResultDomain.failure("更新会话失败");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbChat> deleteChat(TbChat filter) {
        // 1. 校验会话
        TbChat chat = chatMapper.selectChatById(filter.getChatId());
        if (chat == null) {
            return ResultDomain.failure("会话不存在");
        }
        // 判断agent是否是outer
        if(!isOuterAgent(chat.getAgentId())){
            return ResultDomain.failure("智能体不可用");
        }
        // 2. 获取用户ID并校验权限
        LoginDomain loginDomain = LoginUtil.getCurrentLogin();
        String userId = loginDomain.getUser().getUserId();
        if (userId == null) {
            return ResultDomain.failure("用户信息获取失败");
        }
        if (!chat.getUserId().equals(userId)) {
            return ResultDomain.failure("无权删除此会话");
        }

        // 3. 删除会话消息
        chatMessageMapper.deleteMessagesByChatId(filter.getChatId());

        // 4. 删除会话
        TbChat delete = new TbChat();
        delete.setChatId(filter.getChatId());
        int rows = chatMapper.deleteChat(delete);
        if (rows > 0) {
            logger.info("删除会话成功: chatId={}", filter.getChatId());
            return ResultDomain.success("删除会话成功", chat);
        }

        return ResultDomain.failure("删除会话失败");
    }

    @Override
    public ResultDomain<TbChat> getChatList(TbChat filter) {

        // 获取用户ID
        String userId = LoginUtil.getCurrentUserId();
        if (userId == null) {
            return ResultDomain.failure("用户信息获取失败");
        }

        List<TbChat> chatList = chatMapper.selectChatList(filter.getAgentId(), userId);
        return ResultDomain.success("查询成功", chatList);
    }

    @Override
    public ResultDomain<TbChat> getChatPage(PageRequest<TbChat> pageRequest) {
        TbChat filter = pageRequest.getFilter();
        // 判断agent是否是outer（来客才需要校验）
        if (!filter.getUserType() && !isOuterAgent(filter.getAgentId())) {
            return ResultDomain.<TbChat>failure("智能体不可用");
        }
        // 获取用户ID
        String userId = LoginUtil.getCurrentUserId();
        if (userId == null) {
            return ResultDomain.<TbChat>failure("用户信息获取失败");
        }
        filter.setUserId(userId);

        // 分页查询
        PageParam pageParam = pageRequest.getPageParam();
        List<TbChat> chatList = chatMapper.selectChatPage(filter, pageParam);
        long total = chatMapper.countChats(filter);
        pageParam.setTotal((int) total);

        PageDomain<TbChat> pageDomain = new PageDomain<>(pageParam, chatList);
        return ResultDomain.<TbChat>success("查询成功", pageDomain);
    }

    // ====================== 智能体聊天管理 ======================

    @Override
    public ResultDomain<TbChatMessage> getChatMessageList(TbChat filter) {
        // 1. 校验会话
        TbChat chat = chatMapper.selectChatById(filter.getChatId());
        if (chat == null) {
            return ResultDomain.failure("会话不存在");
        }
        // 判断agent是否是outer
        if(!isOuterAgent(chat.getAgentId())){
            return ResultDomain.failure("智能体不可用");
        }
        // 2. 获取用户ID并校验权限
        String userId = LoginUtil.getCurrentUserId();
        if (userId == null) {
            return ResultDomain.failure("用户信息获取失败");
        }
        if (!chat.getUserId().equals(userId)) {
            return ResultDomain.failure("无权查看此会话");
        }

        List<TbChatMessage> messages = chatMessageMapper.selectMessagesByChatId(filter.getChatId());
        return ResultDomain.success("查询成功", messages);
    }

    @Override
    public ResultDomain<String> prepareChatMessageSession(ChatPrepareData prepareData) {
        String agentId = prepareData.getAgentId();
        String chatId = prepareData.getChatId();
        String query = prepareData.getQuery();
        
        // 1. 校验智能体
        ResultDomain<TbAgent> agentResult = agentService.selectAgentById(agentId);
        if (!agentResult.getSuccess() || agentResult.getData() == null || !agentResult.getData().getIsOuter()) {
            return ResultDomain.failure("智能体不存在或不可用");
        }
        TbAgent agent = agentResult.getData();

        // 2. 获取用户ID（根据userType处理来客/员工）
        TbChat chatFilter = new TbChat();
        chatFilter.setAgentId(agentId);
        chatFilter.setUserId(prepareData.getUserId());
        chatFilter.setUserType(prepareData.getUserType());
        
        LoginDomain loginDomain = LoginUtil.getCurrentLogin();
        String userId = loginDomain.getUser().getUserId();
        if (userId == null) {
            return ResultDomain.failure("用户信息获取失败");
        }

        // 3. 校验会话
        if (StringUtils.hasText(chatId)) {
            TbChat chat = chatMapper.selectChatById(chatId);
            if (chat == null) {
                return ResultDomain.failure("会话不存在");
            }
            if (!chat.getUserId().equals(userId)) {
                return ResultDomain.failure("无权操作此会话");
            }
        }

        // 4. 生成临时消息ID（sessionId）
        String sessionId = IdUtil.getSnowflakeId();

        // 5. 存储会话数据到Redis
        Map<String, Object> sessionData = new HashMap<>();
        sessionData.put("agentId", agentId);
        sessionData.put("chatId", chatId);
        sessionData.put("query", query);
        sessionData.put("userId", userId);
        sessionData.put("filesData", prepareData.getFiles());
        sessionData.put("apiKey", agent.getApiKey());
        sessionData.put("outer", agent.getIsOuter());
        sessionData.put("service", prepareData.getService());
        sessionData.put("isGuest", "guest".equals(loginDomain.getUser().getStatus()));

        String cacheKey = CHAT_SESSION_PREFIX + sessionId;
        redisService.set(cacheKey, sessionData, SESSION_TTL, TimeUnit.SECONDS);

        logger.info("准备对话会话: sessionId={}, agentId={}", sessionId, agentId);
        return ResultDomain.success("准备成功", sessionId);
    }

    @Override
    public SseEmitter streamChatMessageWithSse(String sessionId) {
        SseEmitter emitter = new SseEmitter(300000L);

        // 1. 从Redis获取会话数据
        String cacheKey = CHAT_SESSION_PREFIX + sessionId;
        @SuppressWarnings("unchecked")
        Map<String, Object> sessionData = redisService.get(cacheKey, Map.class);

        if (sessionData == null) {
            try {
                emitter.send(SseEmitter.event().name("error").data("{\"message\":\"会话已过期\"}"));
                emitter.complete();
            } catch (IOException e) {
                logger.error("发送错误事件失败", e);
            }
            return emitter;
        }

        // 2. 解析会话数据
        String agentId = (String) sessionData.get("agentId");
        String chatId = (String) sessionData.get("chatId");
        String query = (String) sessionData.get("query");
        String userId = (String) sessionData.get("userId");
        String apiKey = (String) sessionData.get("apiKey");
        String service = (String) sessionData.get("service");
        Boolean outer = (Boolean) sessionData.get("outer");
        Boolean isGuest = (Boolean) sessionData.get("isGuest");

        @SuppressWarnings("unchecked")
        List<DifyFileInfo> filesData = (List<DifyFileInfo>) sessionData.get("filesData");

        // 3. 删除已使用的会话数据
        redisService.delete(cacheKey);

        // 4. 保存用户消息
        String userMessageId = IdUtil.getSnowflakeId();
        TbChatMessage userMessage = new TbChatMessage();
        userMessage.setOptsn(IdUtil.getOptsn());
        userMessage.setMessageId(userMessageId);
        userMessage.setChatId(chatId);
        userMessage.setRole("user");
        userMessage.setContent(query);
        
        // 提取系统文件ID列表保存到消息中
        if (filesData != null && !filesData.isEmpty()) {
            List<String> sysFileIds = filesData.stream()
                .map(DifyFileInfo::getSysFileId)
                .filter(StringUtils::hasText)
                .collect(java.util.stream.Collectors.toList());
            if (!sysFileIds.isEmpty()) {
                userMessage.setFiles(sysFileIds);
            }
        }
        
        chatMessageMapper.insertChatMessage(userMessage);

        // 5. 构建Dify请求
        ChatRequest chatRequest = new ChatRequest();
        chatRequest.setQuery(query);
        chatRequest.setUser(userId);
        chatRequest.setResponseMode("streaming");
        Map<String, Object> inputsMap = new HashMap<>();
        chatRequest.setInputs(inputsMap);  // Dify API 要求 inputs 必传
        // 处理动态知识库的问题
        if(outer && NonUtils.isNotEmpty(service)){
            TbKnowledge filter = new TbKnowledge();
            filter.setService(service);
            filter.setCategory(isGuest?"external":"internal");
            ResultDomain<TbKnowledge> knowledgeRD = knowledgeService.listKnowledges(filter);
            List<String> datasets = new ArrayList<>();
            if(knowledgeRD.getSuccess()){
                datasets = knowledgeRD.getDataList().stream().map(TbKnowledge::getDifyDatasetId).toList();
            }
            inputsMap.put("datasets", JSON.toJSONString(datasets));
            inputsMap.put("dataset_apikey", difyConfig.getKnowledgeApiKey());

        }
        

        if (filesData != null && !filesData.isEmpty()) {
            chatRequest.setFiles(filesData);
        }

        // 6. 准备AI消息记录
        String aiMessageId = IdUtil.getSnowflakeId();
        StringBuilder aiContent = new StringBuilder();

        // 7. 发起流式请求
        difyApiClient.streamChat(chatRequest, apiKey, new StreamCallback() {
            @Override
            public void onEvent(String event, String data) {
                try {
                    // 使用SseEmitter标准格式发送：event: xxx\ndata: xxx
                    emitter.send(SseEmitter.event().name(event).data(data));
                } catch (IOException e) {
                    logger.error("发送SSE事件失败: event={}", event, e);
                }
            }

            @Override
            public void onMessage(String content) {
                aiContent.append(content);
            }

            @Override
            public void onMessageEnd(String data) {
                // 从message_end事件中提取difyMessageId
                String difyMessageId = null;
                try {
                    JSONObject json = JSONObject.parseObject(data);
                    if (json != null && json.containsKey("message_id")) {
                        difyMessageId = json.getString("message_id");
                    }
                } catch (Exception e) {
                    logger.warn("解析difyMessageId失败: {}", e.getMessage());
                }

                // 保存AI回复消息
                TbChatMessage aiMessage = new TbChatMessage();
                aiMessage.setOptsn(IdUtil.getOptsn());
                aiMessage.setMessageId(aiMessageId);
                aiMessage.setDifyMessageId(difyMessageId);
                aiMessage.setChatId(chatId);
                aiMessage.setRole("ai");
                aiMessage.setContent(aiContent.toString());
                chatMessageMapper.insertChatMessage(aiMessage);

                logger.info("对话完成: chatId={}, aiMessageId={}, difyMessageId={}", chatId, aiMessageId, difyMessageId);
            }

            @Override
            public void onComplete() {
                try {
                    emitter.complete();
                } catch (Exception e) {
                    logger.error("完成SSE失败", e);
                }
            }

            @Override
            public void onError(Throwable throwable) {
                logger.error("流式对话异常", throwable);
                try {
                    JSONObject errorData = new JSONObject();
                    errorData.put("message", throwable.getMessage());
                    emitter.send(SseEmitter.event().name("error").data(errorData.toJSONString()));
                    emitter.complete();
                } catch (IOException e) {
                    logger.error("发送错误事件失败", e);
                }
            }
        });

        return emitter;
    }

    @Override
    public ResultDomain<Boolean> stopChatMessageByTaskId(TbChat filter, String taskId) {
        // 1. 获取智能体
        ResultDomain<TbAgent> agentResult = agentService.selectAgentById(filter.getAgentId());
        if (!agentResult.getSuccess() || agentResult.getData() == null || !agentResult.getData().getIsOuter()) {
            return ResultDomain.failure("智能体不存在");
        }
        TbAgent agent = agentResult.getData();

        // 2. 获取用户ID
        String userId = LoginUtil.getCurrentUserId();
        if (userId == null) {
            return ResultDomain.failure("用户信息获取失败");
        }

        try {
            // 3. 调用Dify停止接口
            difyApiClient.stopChatMessage(taskId, userId, agent.getApiKey());
            logger.info("停止对话成功: taskId={}", taskId);
            return ResultDomain.success("停止成功", true);
        } catch (Exception e) {
            logger.error("停止对话失败: taskId={}", taskId, e);
            return ResultDomain.failure("停止对话失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<Boolean> commentChatMessage(TbChat filter, String messageId, String comment) {
        // 1. 校验消息
        TbChatMessage message = chatMessageMapper.selectMessageById(messageId);
        if (message == null) {
            return ResultDomain.failure("消息不存在");
        }

        // 2. 获取用户ID
        String userId = LoginUtil.getCurrentUserId();
        if (userId == null) {
            return ResultDomain.failure("用户信息获取失败");
        }

        // 3. 更新评价
        TbChatMessage update = new TbChatMessage();
        update.setMessageId(messageId);
        update.setComment(comment);

        int rows = chatMessageMapper.updateChatMessage(update);
        if (rows > 0) {
            // 4. 同步到Dify（转换评价格式，使用difyMessageId）
            if (StringUtils.hasText(message.getDifyMessageId())) {
                ResultDomain<TbAgent> agentResult = agentService.selectAgentById(filter.getAgentId());
                if (agentResult.getSuccess() && agentResult.getData() != null) {
                    TbAgent agent = agentResult.getData();
                    String rating = "like".equals(comment) ? "like" : ("dislike".equals(comment) ? "dislike" : null);
                    try {
                        difyApiClient.submitMessageFeedback(message.getDifyMessageId(), rating, userId, comment, agent.getApiKey());
                    } catch (Exception e) {
                        logger.warn("同步评价到Dify失败: difyMessageId={}", message.getDifyMessageId(), e);
                    }
                }
            }

            logger.info("评价消息成功: messageId={}, comment={}", messageId, comment);
            return ResultDomain.success("评价成功", true);
        }

        return ResultDomain.failure("评价失败");
    }
}
