package com.seer.teach.teacher.stateMachine.action.lecture;

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.common.enums.MessageEnums;
import com.seer.teach.common.enums.teacher.LessonStateEnum;
import com.seer.teach.common.enums.teacher.LessonStateEvent;
import com.seer.teach.teacher.common.dto.LessonContextDTO;
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.processor.chat.ChatStreamProcessor;
import com.seer.teach.teacher.service.LlmSseService;
import com.seer.teach.teacher.service.prompt.impl.BasePromptService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.action.Action;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

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

/**
 * 讲课超时结束动作实现类。
 * 当前状态机在进入“讲课完成超时”状态时执行该动作，
 * 主要用于触发模型主动提问流程，并通过 SSE 流式处理大模型响应。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LectureFinishTimeOutAction extends BasePromptService implements Action<LessonStateEnum, LessonStateEvent> {

    private final ChatStreamProcessor chatStreamProcessor;

    private final LlmSseService llmSseService;

    /**
     * 获取当前模块标识符。
     *
     * @return 模块名："modelAsk"
     */
    @Override
    public String getModule() {
        return "modelAsk";
    }

    /**
     * 获取功能名称描述。
     *
     * @return 功能名称："模型主动提问"
     */
    @Override
    public String getFunctionName() {
        return "模型主动提问";
    }

    /**
     * 获取角色 ID。
     *
     * @return 角色编号：7
     */
    @Override
    public Integer getRoleId() {
        return 7;
    }

    /**
     * 执行状态转换时的动作逻辑。
     * 包括构建与大模型交互的消息、发起异步聊天请求以及流式处理响应等操作。
     *
     * @param stateContext 状态机上下文对象，包含当前状态和扩展数据
     */
    @Override
    public void execute(StateContext<LessonStateEnum, LessonStateEvent> stateContext) {
        // 提取课程上下文和用户ID
        LessonContextDTO ctx = stateContext.getExtendedState().get("ctx", LessonContextDTO.class);
        Integer userId = Integer.valueOf(stateContext.getStateMachine().getId());
        log.info("用户[{}],讲课音频播放完毕 模型主动提问", userId);

        // 根据用户ID查询其绑定设备信息
        String device = ctx.getTeachDTO().getDevice();

        // 构造与大模型交互的消息列表
        List<Message> messages = getPrompt(ctx);

        // 生成本次会话唯一ID
        Integer sessionId = TeacherUtils.generateSessionId(userId, ctx, messages);

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

        // 发起异步聊天请求并获得响应数据流
        Flux<LlmChatDTO> flux = llmSseService.aiChat(llmReq);

        // 构建音频发布通道名称
        String channelName = LlmAudioPublisher.getChannel(device + sessionId);

        // 使用聊天处理器对结果进行流式处理和输出
        chatStreamProcessor.process(userId, llmReq, device, flux, channelName);
    }

    /**
     * 构建与大模型交互所需的提示消息列表。
     * 包含系统级提示和用户级提示两部分内容。
     *
     * @param ctx 课程上下文对象
     * @return 完整的消息列表（包括系统消息和用户消息）
     */
    private List<Message> getPrompt(LessonContextDTO ctx) {
        // 将课程上下文放入线程本地变量中供后续使用
        PromptContextHolder.put(PromptContextHolder.LESSON, ctx);

        // 获取基础提示模板
        Map<String, List<Text>> prompts = this.generatePromptMessages();

        // 分别提取系统和用户的初始提示部分
        List<Text> system = prompts.get(MessageEnums.SYSTEM.getMessage());
        List<Text> user = prompts.get(MessageEnums.USER.getMessage());

        // 组装成完整的Message对象
        Message systemMessage = Message.system(system);
        Message userMessage = Message.user(user);

        // 合并为最终的消息列表
        List<Message> messages = new ArrayList<>();
        messages.add(systemMessage);
        messages.add(userMessage);
        return messages;
    }

}
