package com.seer.teach.teacher.service.prompt.impl;

import com.seer.teach.common.cache.LlmAudioPublisher;
import com.seer.teach.common.context.PromptContextHolder;
import com.seer.teach.common.dto.mq.LlmChatDTO;
import com.seer.teach.teacher.common.dto.ArticleDTO;
import com.seer.teach.teacher.common.dto.ReadingStatusDTO;
import com.seer.teach.teacher.common.llm.sse.req.LlmSseChatReq;
import com.seer.teach.teacher.common.llm.sse.req.Message;
import com.seer.teach.teacher.common.llm.sse.req.Text;
import com.seer.teach.teacher.common.utils.TeacherUtils;
import com.seer.teach.teacher.common.utils.UserStatusCacheUtils;
import com.seer.teach.teacher.module.entity.BookChaptersEntity;
import com.seer.teach.teacher.module.entity.BooksEntity;
import com.seer.teach.teacher.module.entity.TreasuryBoxArticlesEntity;
import com.seer.teach.teacher.processor.chat.ReadChatStreamProcessor;
import com.seer.teach.teacher.service.BookChaptersService;
import com.seer.teach.teacher.service.BooksService;
import com.seer.teach.teacher.service.LlmSseService;
import com.seer.teach.teacher.service.TreasuryBoxArticlesService;
import com.seer.teach.teacher.service.impl.ReadCountdownManagerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 阅读提问服务实现类。
 * <p>
 * 提供处理用户在阅读过程中提出问题的功能，包括构建上下文、调用大模型进行对话，并通过 SSE 流式返回结果。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReadQuestionService extends BasePromptService {

    private final BookChaptersService bookChaptersService;

    private final BooksService booksService;

    private final TreasuryBoxArticlesService treasuryBoxArticlesService;

    private final LlmSseService llmSseService;

    private final ReadCountdownManagerService readCountdownManagerService;

    private final ReadChatStreamProcessor readChatStreamProcessor;

    /**
     * 获取当前模块名称。
     *
     * @return 模块名："readQuestion"
     */
    @Override
    public String getModule() {
        return "readQuestion";
    }

    /**
     * 获取功能名称。
     *
     * @return 功能中文名："阅读提问"
     */
    @Override
    public String getFunctionName() {
        return "阅读提问";
    }

    /**
     * 获取角色 ID。
     *
     * @return 角色标识符：1（教师）
     */
    @Override
    public Integer getRoleId() {
        return 1;
    }

    /**
     * 处理用户的阅读相关聊天请求。
     * <p>
     * 此方法会取消倒计时任务，获取用户当前阅读状态并插入提示词上下文，
     * 然后构造与大语言模型交互的消息列表，发起 SSE 聊天请求，并将响应流交给处理器进行后续处理。
     *
     * @param userId      用户ID
     * @param userQuestion 用户提出的问题内容
     * @param device      设备类型，用于生成频道名
     */
    public void handlerUserReadChat(Integer userId, String userQuestion, String device) {
        // 取消该用户的倒计时任务
        readCountdownManagerService.cancelCountdown(userId);

        // 获取用户当前的阅读状态信息
        ReadingStatusDTO reading = UserStatusCacheUtils.getReading(userId);

        // 将文章内容等上下文信息注入到 Prompt 上下文中
        insertPromptContext(reading);

        // 生成完整的提示词模板
        Map<String, List<Text>> prompt = super.generatePromptMessages();
        List<Message> messages = new ArrayList<>();
        prompt.forEach((role, contentList) -> {
            messages.add(new Message(role, contentList));
        });

        // 生成唯一的会话 ID 和通道名称
        Integer sessionId = TeacherUtils.generateSessionId(userId, messages);
        String channelName = LlmAudioPublisher.getChannel(device + sessionId);

        // 创建大模型聊天请求对象
        LlmSseChatReq llmReq = new LlmSseChatReq(sessionId, userId, messages);

        // 发起 AI 对话请求并获得响应数据流
        Flux<LlmChatDTO> llmFlux = llmSseService.aiChat(llmReq);

        // 使用专门的处理器来消费并转发响应流
        readChatStreamProcessor.process(userId, llmReq, device, llmFlux, channelName);
    }

    /**
     * 根据用户的阅读状态，从数据库中加载对应的文章或章节内容，
     * 并将其封装成 ArticleDTO 放入 Prompt 上下文环境中。
     *
     * @param readingStatus 当前用户的阅读状态信息
     */
    private void insertPromptContext(ReadingStatusDTO readingStatus) {
        String bookName = "";
        String content = "";

        if (readingStatus.getType().equals(5)) {
            // 类型为5表示是书籍章节
            BookChaptersEntity chapter = bookChaptersService.getById(readingStatus.getChapterId());
            BooksEntity book = booksService.getById(chapter.getBookId());
            bookName = book.getTitle();
            content = chapter.getContent();
        } else {
            // 其他情况默认为宝库箱中的文章
            TreasuryBoxArticlesEntity book = treasuryBoxArticlesService.getById(readingStatus.getChapterId());
            bookName = book.getTitle();
            content = book.getContent();
        }

        // 将文章标题和正文存入上下文环境，供提示词使用
        PromptContextHolder.put(PromptContextHolder.ARTICLE_KEY, new ArticleDTO(bookName, content));
    }

}
