package org.jk.rag.service.impl;

import cn.hutool.log.Log;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jk.common.core.config.DeepseekConfig;
import org.jk.common.mybatis.core.page.PageQuery;
import org.jk.common.satoken.utils.LoginHelper;
import org.jk.rag.domain.Dataset;
import org.jk.rag.domain.EvaluationTask;
import org.jk.rag.domain.entity.*;
import org.jk.rag.domain.vo.DatasetVo;
import org.jk.rag.domain.vo.EvaluationTaskVo;
import org.jk.rag.mapper.JkAppInfoMapper;
import org.jk.rag.mapper.JkApplicationMapper;
import org.jk.rag.mapper.JkDatasetMapper;
import org.jk.rag.mapper.JkEvaluationTaskMapper;
import org.jk.rag.service.IJkDatasetService;
import org.jk.rag.service.IJkEvaluationTaskService;
import org.jk.rag.utils.RedisSerialRateLimiter;
import org.redisson.api.RBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 用户 业务层处理
 *
 * @author jk
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class JkEvaluationTaskServiceImpl implements IJkEvaluationTaskService {

    private static final Logger logger = LoggerFactory.getLogger(JkEvaluationTaskServiceImpl.class);

    private final JkEvaluationTaskMapper evaluationTaskMapper;

    private final JkApplicationMapper applicationMapper;

    private final JkAppInfoMapper appInfoMapper;

    private final DeepseekConfig deepseekConfig;

    private final JkDatasetMapper datasetMapper;

    @Override
    public Page<EvaluationTaskVo> selectPageList(String name, PageQuery pageQuery) {
        Page<EvaluationTaskVo> page = evaluationTaskMapper.selectPageList(name,pageQuery.build());
        return page;
    }

    @Override
    public Long insertEvaluationTask(EvaluationTaskVo evaluationTaskVo) {
        EvaluationTask evaluationTask = new EvaluationTask();
        BeanUtils.copyProperties(evaluationTaskVo, evaluationTask);
        evaluationTaskMapper.insert(evaluationTask);
        return evaluationTask.getTaskId();
    }

    @Override
    public boolean checkName(String name) {
        Integer taskCount = evaluationTaskMapper.checkName(name);
        if (null != taskCount && taskCount > 0) {
            return false;
        }
        return true;
    }

    @Override
    public void edit(EvaluationTaskVo evaluationTaskVo) {
        EvaluationTask evaluationTask = new EvaluationTask();
        BeanUtils.copyProperties(evaluationTaskVo,evaluationTask);
        evaluationTaskMapper.updateById(evaluationTask);
    }

    @Async
    @Override
    public CompletableFuture<Integer> beginTask(EvaluationTaskVo evaluationTaskVo) {

        return CompletableFuture.supplyAsync(() -> {
            try {
                JSONObject json = new JSONObject();
                DatasetVo datasetVo = datasetMapper.selectVoById(evaluationTaskVo.getEvaluationData());
                json.put("file_url", datasetVo.getUrl());
                json.put("model", evaluationTaskVo.getModel());
                JkApplication application = applicationMapper.selectOpenApplication(
                    JkApplication.builder().appId(evaluationTaskVo.getReviewRag()).build());
                json.put("knowledge_ids", Arrays.asList(application.getKnowledgeIds().split(",")));
                json.put("embedding_id", evaluationTaskVo.getEmbeddingId());
                json.put("top_p", application.getTopP());
                json.put("max_tokens", application.getMaxToken());
                json.put("task_id",evaluationTaskVo.getTaskId());
                json.put("user_id",evaluationTaskVo.getCreateBy());
                json.put("tenant_id",evaluationTaskVo.getTenantId());
                JkAppInfo appInfo = appInfoMapper.selectAppInfoByAppId(evaluationTaskVo.getReviewRag());
                if(null != appInfo) {
                    String appInfoJsonString = appInfo.getAppInfo();
                    JSONObject jsonObject = JSONObject.parseObject(appInfoJsonString);
                    json.put("slice_count", jsonObject.getString("sliceCount"));
                }
                pythonBeginTask(json);
                return 1;
            } catch (Exception e) {
                logger.error("评测任务处理失败", e);
                return 0;
            }

        });
    }

    @Override
    public void deleteById(Long taskId) {
        evaluationTaskMapper.deleteById(taskId);
    }

    public JSONObject pythonBeginTask(JSONObject json) {
        String url = deepseekConfig.getBaseurl() + deepseekConfig.getEvaluate();

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), json.toJSONString());
        Request request = buildPostRequest(url, requestBody);
        OkHttpClient client = buildOkHttpClient();
        Response response = null;
        try {
            response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                String body = response.body().string();
                JSONObject obj = JSON.parseObject(body);
                Integer code = obj.getInteger("code");
                if (code == 200) {
                    logger.info("评测任务调用python接口成功,返回内容：{}", body);
                } else {
                    logger.info("评测任务调用python接口失败,返回内容：{}", body);
                }
                return obj;
            } else {
                logger.error("评测任务调用python接口失败返回code：{}", response.code());
                return null;
            }
        } catch (IOException e) {
            logger.error("评测任务调用python接口失败", e.getMessage());
            return null;
        }
    }

    private OkHttpClient buildOkHttpClient() {
        return new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(50, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.MINUTES)
            .build();
    }

    private Request buildPostRequest(String url, RequestBody requestBody) {
        return new Request.Builder()
            .addHeader("User-Agent", "insomnia/10.3.1")
            .addHeader("Content-Type", "application/json")
            .url(url).post(requestBody).build();
    }


}
