package com.qmth.boot.core.ai.service;

import com.qmth.boot.core.ai.client.LlmApiClient;
import com.qmth.boot.core.ai.model.llm.*;
import com.qmth.boot.core.retrofit.utils.SignatureInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * AI相关功能服务
 */
@Service
public class AiService {

    private static final Pattern score_pattern = Pattern.compile("[^\\d]*(\\d+)[^\\d]*");

    @Resource
    private LlmApiClient llmApiClient;

    /**
     * 获取当前机构大模型接口调用次数余额
     *
     * @param appType   大模型接口应用类型
     * @param signature 使用当前机构AK作为鉴权信息
     * @return 调用次数余额
     */
    public LlmAppBalance getLlmBalance(@NotNull LlmAppType appType, @NotNull SignatureInfo signature) {
        return llmApiClient.getBalance(signature, appType);
    }

    /**
     * 使用自定义提示词进行自动命题
     *
     * @param request   大模型通用Chat请求
     * @param signature 使用当前机构AK作为鉴权信息
     * @return 大模型返回的文本集合
     */
    public List<String> autoGenerateQuestion(@NotNull ChatRequest request, @NotNull SignatureInfo signature) {
        ChatResult result = llmApiClient.chat(signature, LlmAppType.AUTO_GENERATE_QUESTION, request);
        return result.getChoices().stream().filter(choice -> choice.getMessage().getRole() == ChatRole.assistant)
                .map(choice -> choice.getMessage().getContent()).collect(Collectors.toList());
    }

    /**
     * 使用预设模版进行自动命题
     *
     * @param param     基于预设模版的参数对象，可以使用Map或自定义Object
     * @param signature 使用当前机构AK作为鉴权信息
     * @return 大模型返回的文本集合
     */
    public List<String> autoGenerateQuestion(@NotNull Object param, @NotNull SignatureInfo signature) {
        ChatResult result = llmApiClient.chatTemplate(signature, LlmAppType.AUTO_GENERATE_QUESTION, param);
        return result.getChoices().stream().filter(choice -> choice.getMessage().getRole() == ChatRole.assistant)
                .map(choice -> choice.getMessage().getContent()).collect(Collectors.toList());
    }

    /**
     * 使用预设模版进行自动判分，考生作答为文本
     *
     * @param request   自动判分请求参数
     * @param signature 使用当前机构AK作为鉴权信息
     * @return 得分率，保留最多三位小数；null表示无法获取判分结果
     */
    public AutoScoreResult autoScore(@NotNull @Validated AutoScoreRequest request, @NotNull SignatureInfo signature) {
        ChatResult result = llmApiClient.chatTemplate(signature, LlmAppType.AUTO_SCORE, request);
        String text = result.getChoices().stream().filter(choice -> choice.getMessage().getRole() == ChatRole.assistant)
                .map(choice -> choice.getMessage().getContent()).findFirst().orElse("");
        try {
            AutoScoreResult scoreResult = new AutoScoreResult();
            //依据总分与步骤分计算最大精度
            int scale = Math
                    .max(getDecimalPlaces(request.getIntervalScore()), getDecimalPlaces(request.getTotalScore()));
            int stepCount = request.getStandardAnswer().size();
            String[] scores = StringUtils.split(text.replaceAll("，", ","), ",");
            double[] scoreArray = new double[stepCount];
            for (int i = 0; i < stepCount; i++) {
                //根据得分率与步骤总分计算实际得分，按最大精度保留小数位数
                double score = BigDecimal.valueOf(
                        Math.min(Integer.parseInt(scores[i].trim()), 100) * request.getStandardAnswer().get(i)
                                .getScore()).divide(BigDecimal.valueOf(100), scale, RoundingMode.HALF_UP).doubleValue();
                scoreArray[i] = score;
            }
            scoreResult.setStepScore(scoreArray);
            scoreResult.setTotalScore(
                    Arrays.stream(scoreArray).mapToObj(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add)
                            .doubleValue());
            return scoreResult;
        } catch (Exception e) {
            return null;
        }
    }

    private static int getDecimalPlaces(double value) {
        return Math.max(0, BigDecimal.valueOf(value).stripTrailingZeros().scale());
    }
}
