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

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.teacher.convert.LlmRequestLogsConvert;
import com.seer.teach.teacher.module.entity.LlmRequestLogsEntity;
import com.seer.teach.teacher.module.mapper.LlmRequestLogsMapper;
import com.seer.teach.teacher.service.LlmRequestLogsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Wang
 * @since 2025-10-29 19:08:14
 */
@Slf4j
@Service
public class LlmRequestLogsServiceImpl extends ServiceImpl<LlmRequestLogsMapper, LlmRequestLogsEntity> implements LlmRequestLogsService {

    private static final String SSE_REQUEST_TYPE = "sse";

    private static final String REQUEST_TYPE = "request";

    /**
     * 异步保存 SSE 类型的请求日志
     *
     * @param userId        用户ID
     * @param requestDesc   请求描述
     * @param sessionId     会话ID
     * @param reqParams     请求参数对象，将被序列化为 JSON 字符串
     * @param keyParameters 关键参数信息
     * @param <T>           请求参数类型
     */
    @Override
    @Async("logExecutor")
    public <T> void saveSseLog(Integer userId, String requestDesc, Integer sessionId, T reqParams, T keyParameters) {
        try {
            // 将请求参数转换为 JSON 字符串
            String reqString = JSONUtil.toJsonStr(reqParams);
            String keyParametersString = JSONUtil.toJsonStr(keyParameters);
            // 构造日志实体
            LlmRequestLogsEntity log = LlmRequestLogsConvert.INSTANCE.toLogsEntity(userId,
                    sessionId,
                    SSE_REQUEST_TYPE,
                    requestDesc,
                    keyParametersString,
                    reqString
            );
            // 设置开始时间并保存
            log.setStartTime(LocalDateTime.now());
            save(log);
        } catch (Exception e) {
            log.error("SSE 日志保存失败：sessionId={}，desc={}，原因={}", sessionId, requestDesc, e.getMessage(), e);
        }
    }

    /**
     * 异步保存普通请求类型的日志
     *
     * @param userId        用户ID
     * @param requestDesc   请求描述
     * @param sessionId     会话ID
     * @param reqParams     请求参数对象，将被序列化为 JSON 字符串
     * @param keyParameters 关键参数信息
     * @param <T>           请求参数类型
     */
    @Async("logExecutor")
    @Override
    public <T> void saveRequestLog(Integer userId, String requestDesc, Integer sessionId, T reqParams, T keyParameters) {
        try {
            // 将请求参数转换为 JSON 字符串
            String reqString = JSONUtil.toJsonStr(reqParams);
            String keyParametersString = JSONUtil.toJsonStr(keyParameters);
            // 构造日志实体
            LlmRequestLogsEntity log = LlmRequestLogsConvert.INSTANCE.toLogsEntity(userId,
                    sessionId,
                    REQUEST_TYPE,
                    requestDesc,
                    keyParametersString,
                    reqString
            );
            // 设置开始时间并保存
            log.setStartTime(LocalDateTime.now());
            save(log);
        } catch (Exception e) {
            log.error("SSE 日志保存失败：sessionId={}，desc={}，原因={}", sessionId, requestDesc, e.getMessage(), e);
        }
    }

    /**
     * 异步更新响应日志内容
     *
     * @param sessionId    会话ID
     * @param responseData 响应数据，可变参数，将被序列化为 JSON 字符串
     * @param <T>          响应数据类型
     */
    @Override
    @Async("logExecutor")
    public <T> void updateResponseLog(Integer sessionId, T responseData) {
        try {
            // 将响应数据转换为 JSON 字符串
            String respString = JSONUtil.toJsonStr(responseData);
            // 查询对应的日志记录
            LlmRequestLogsEntity one = getOne(new LambdaQueryWrapper<LlmRequestLogsEntity>()
                    .eq(LlmRequestLogsEntity::getSessionId, sessionId));
            // 更新响应内容、结束时间及耗时
            one.setResponse(respString);
            one.setEndTime(LocalDateTime.now());
            one.setUseTime((int) Duration.between(one.getStartTime(), one.getEndTime()).toMillis());
            updateById(one);
        } catch (Exception e) {
            log.error("更新  响应日志失败：sessionId={}，原因={}", sessionId, e.getMessage(), e);
        }
    }

    /**
     * 异步更新错误日志状态和错误信息
     *
     * @param sessionId    会话ID
     * @param errorMessage 错误消息
     */
    @Override
    @Async("logExecutor")
    public void updateErrorLog(Integer sessionId, String errorMessage) {
        try {
            // 更新日志状态为错误（status=1）并设置错误信息
            update(new LambdaUpdateWrapper<LlmRequestLogsEntity>()
                    .eq(LlmRequestLogsEntity::getSessionId, sessionId)
                    .set(LlmRequestLogsEntity::getStatus, 1)
                    .set(LlmRequestLogsEntity::getErrorMessage, errorMessage));
        } catch (Exception e) {
            log.error("更新 SSE 错误日志失败：sessionId={}，原因={}", sessionId, e.getMessage(), e);
        }
    }

    /**
     * 异步更新空响应日志内容
     *
     * @param sessionId 会话ID
     */
    @Override
    @Async("logExecutor")
    public void updateEmptyResponseLog(Integer sessionId) {
        try {
            // 查询对应的日志记录
            LlmRequestLogsEntity one = getOne(new LambdaQueryWrapper<LlmRequestLogsEntity>()
                    .eq(LlmRequestLogsEntity::getSessionId, sessionId));
            // 设置响应内容为“数据为空”的提示信息
            one.setResponse(ResultCodeEnum.REQUEST_LLM_FAIL.getMsg());
            // 设置结束时间和耗时
            one.setEndTime(LocalDateTime.now());
            one.setUseTime((int) Duration.between(one.getStartTime(), one.getEndTime()).toMillis());
            updateById(one);
        } catch (Exception e) {
            log.error("更新 SSE 空响应日志失败：sessionId={}，原因={}", sessionId, e.getMessage(), e);
        }
    }
}
