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

import com.seer.teach.common.enums.MessageEnums;
import com.seer.teach.teacher.common.llm.resp.BboxLocationResult;
import com.seer.teach.teacher.common.llm.resp.ProcessUploadResult;
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.service.AiModelCallService;
import com.seer.teach.teacher.service.LlmRequestService;
import com.seer.teach.teacher.service.platform.LlmResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

/**
 * 题目完整性校验服务实现类。
 * <p>
 * 该类用于判断上传的图片中是否包含完整的题目信息。通过调用大模型接口分析 OCR 结果及对应图像，
 * 判断每道题目的图像是否满足“题目完整”的标准，并将符合要求的结果返回。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ValidateQuestionIntegrity extends BasePromptService {

    /**
     * 异步执行器，用于并发执行多个 LLM 调用任务。
     */
    private final Executor llmExecutor;

    private final AiModelCallService aiModelCallService;

    private final LlmRequestService llmRequestService;


    /**
     * 获取模块名称。
     *
     * @return 返回模块名："validateQuestions"
     */
    @Override
    public String getModule() {
        return "validateQuestions";
    }

    /**
     * 获取功能名称。
     *
     * @return 功能中文描述："校验题目是否完整"
     */
    @Override
    public String getFunctionName() {
        return "校验题目是否完整";
    }

    /**
     * 获取角色 ID。
     *
     * @return 角色编号：2（教师端相关）
     */
    @Override
    public Integer getRoleId() {
        return 2;
    }


    /**
     * 校验题目完整性主方法。
     * <p>
     * 对传入的 OCR 提取结果进行逐项验证，结合对应的图像地址，使用 AI 大模型判断其是否构成一个完整题目。
     *
     * @param userId     用户ID，标识请求来源用户
     * @param ocrResults OCR识别结果列表，包含各题目的位置与文本信息
     * @return 符合完整性条件的 OCR 结果列表
     */
    public List<BboxLocationResult> validateQuestionIntegrity(
            Integer userId,
            List<BboxLocationResult> ocrResults) {
        // 构建基础提示消息模板
        Map<String, List<Text>> basePrompt = super.generatePromptMessages();

        // 使用线程安全集合存储符合条件的结果
        List<BboxLocationResult> results = Collections.synchronizedList(new ArrayList<>());

        // 并发处理所有 OCR 结果
        CompletableFuture.allOf(
                ocrResults.stream()
                        .map(ocrResult -> CompletableFuture.runAsync(() -> {
                            // 请求上传并获取裁剪后的图像 URL
                            ProcessUploadResult process =
                                    llmRequestService.requestProcessUpload(userId, ocrResult.getCropedImg());

                            // 构造发送给大模型的消息内容
                            List<Message> reqMessages = new ArrayList<>();

                            // 添加系统级提示词
                            reqMessages.add(new Message(
                                    MessageEnums.SYSTEM.getMessage(),
                                    deepCopy(basePrompt.get(MessageEnums.SYSTEM.getMessage()))
                            ));

                            // 添加用户级提示词并附加图像 URL
                            List<Text> userContent = deepCopy(basePrompt.get(MessageEnums.USER.getMessage()));
                            userContent.add(Text.imageUrl(process.getImage_url().getUrl()));
                            reqMessages.add(new Message(
                                    MessageEnums.USER.getMessage(),
                                    userContent
                            ));

                            // 发起大模型调用
                            LlmResponse llmResp = aiModelCallService.callModel(
                                    getModule(), reqMessages, null, userId
                            );

                            // 解析响应内容，若包含 true 表示题目完整
                            String content = llmResp.getChoices().get(0).getMessage().getContent();
                            if (content.contains("true")) {
                                results.add(ocrResult); // 将完整题目加入结果集
                            }
                        }, llmExecutor)) // 使用指定线程池异步执行
                        .toArray(CompletableFuture[]::new)
        ).join(); // 等待所有任务完成

        return results;
    }

    /**
     * 文本对象列表深拷贝工具方法。
     * <p>
     * 由于提示词模板可能被复用且需要动态追加内容，因此必须保证每次发送给模型的消息是独立副本。
     *
     * @param list 原始文本对象列表
     * @return 新创建的、具有相同内容的新列表
     */
    private List<Text> deepCopy(List<Text> list) {
        List<Text> copy = new ArrayList<>();
        for (Text t : list) {
            Text.Image_url imgCopy = null;
            if (t.getImage_url() != null) {
                imgCopy = new Text.Image_url(t.getImage_url().getUrl());
            }
            copy.add(new Text(
                    t.getType(),
                    t.getText(),
                    imgCopy
            ));
        }
        return copy;
    }
}
