package com.seer.teach.openapi.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.openapi.convert.SnCallLogsConvert;
import com.seer.teach.openapi.entity.SnCallLogsEntity;
import com.seer.teach.openapi.mapper.SnCallLogsMapper;
import com.seer.teach.openapi.service.SnCallLogsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

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

/**
 * SSE 和请求日志服务实现类
 * <p>
 * 提供对 SSE 请求、普通请求的日志记录功能，包括请求参数、响应结果、错误信息等的异步保存与更新。
 * </p>
 */
@Slf4j
@Service
public class SnCallLogsServiceImpl extends ServiceImpl<SnCallLogsMapper, SnCallLogsEntity> implements SnCallLogsService {

    private static final String SSE_REQUEST_TYPE = "sse";

    private static final String REQUEST_TYPE = "request";

    /**
     * 异步保存 SSE 类型请求日志
     *
     * @param sn             设备序列号
     * @param requestDesc    请求描述信息
     * @param sessionId      会话 ID
     * @param reqParams      请求参数对象（将被序列化为 JSON 字符串）
     * @param keyParameters  关键参数对象（将被序列化为 JSON 字符串）
     * @param <T>            泛型类型，支持任意可序列化为 JSON 的对象
     */
    @Override
    @Async("logExecutor")
    public <T> void saveSseLog(String sn, String requestDesc, Integer sessionId, T reqParams, T keyParameters) {
        try {
            // 将请求参数转换为 JSON 字符串
            String reqString = JSONUtil.toJsonStr(reqParams);
            String keyParametersString = JSONUtil.toJsonStr(keyParameters);
            // 构造日志实体
            SnCallLogsEntity log = SnCallLogsConvert.INSTANCE.toLogsEntity(sn,
                    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 sn             设备序列号
     * @param requestDesc    请求描述信息
     * @param sessionId      会话 ID
     * @param reqParams      请求参数对象（将被序列化为 JSON 字符串）
     * @param keyParameters  关键参数对象（将被序列化为 JSON 字符串）
     * @param <T>            泛型类型，支持任意可序列化为 JSON 的对象
     */
    @Async("logExecutor")
    @Override
    public <T> void saveRequestLog(String sn, String requestDesc, Integer sessionId, T reqParams, T keyParameters) {
        try {
            // 将请求参数转换为 JSON 字符串
            String reqString = JSONUtil.toJsonStr(reqParams);
            String keyParametersString = JSONUtil.toJsonStr(keyParameters);
            // 构造日志实体
            SnCallLogsEntity log = SnCallLogsConvert.INSTANCE.toLogsEntity(sn,
                    sessionId,
                    REQUEST_TYPE,
                    requestDesc,
                    keyParametersString,
                    reqString
            );
            // 设置开始时间并保存
            log.setStartTime(LocalDateTime.now());
            save(log);
        } catch (Exception e) {
            log.error("请求日志保存失败：sessionId={}，desc={}，原因={}", sessionId, requestDesc, e.getMessage(), e);
        }
    }

    /**
     * 异步更新响应日志内容
     *
     * @param sessionId    会话 ID
     * @param responseData 响应数据对象（将被序列化为 JSON 字符串）
     * @param <T>          泛型类型，支持任意可序列化为 JSON 的对象
     */
    @Override
    @Async("logExecutor")
    public <T> void updateResponseLog(Integer sessionId, T responseData) {
        try {
            // 将响应数据转换为 JSON 字符串
            String respString = JSONUtil.toJsonStr(responseData);
            // 查询对应的日志记录
            SnCallLogsEntity one = getOne(new LambdaQueryWrapper<SnCallLogsEntity>()
                    .eq(SnCallLogsEntity::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<SnCallLogsEntity>()
                    .eq(SnCallLogsEntity::getSessionId, sessionId)
                    .set(SnCallLogsEntity::getStatus, 1)
                    .set(SnCallLogsEntity::getErrorMessage, errorMessage));
        } catch (Exception e) {
            log.error("更新错误日志失败：sessionId={}，原因={}", sessionId, e.getMessage(), e);
        }
    }

    /**
     * 异步更新空响应日志内容
     *
     * @param sessionId 会话 ID
     */
    @Override
    @Async("logExecutor")
    public void updateEmptyResponseLog(Integer sessionId) {
        try {
            // 查询对应的日志记录
            SnCallLogsEntity one = getOne(new LambdaQueryWrapper<SnCallLogsEntity>()
                    .eq(SnCallLogsEntity::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("更新空响应日志失败：sessionId={}，原因={}", sessionId, e.getMessage(), e);
        }
    }

}
