package cn.iocoder.yudao.module.llm.service.modelservice;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.llm.controller.admin.modelservice.vo.ModelServicePageReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.modelservice.vo.ModelServiceRespVO;
import cn.iocoder.yudao.module.llm.controller.admin.modelservice.vo.ModelServiceSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.finetuningtask.FineTuningTaskDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelservice.ModelServiceDO;
import cn.iocoder.yudao.module.llm.dal.mysql.finetuningtask.FineTuningTaskMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper;
import cn.iocoder.yudao.module.llm.framework.backend.config.LLMBackendProperties;
import cn.iocoder.yudao.module.llm.service.application.ApplicationService;
import cn.iocoder.yudao.module.llm.service.async.AsyncModelServiceService;
import cn.iocoder.yudao.module.llm.service.finetuningtask.FineTuningTaskService;
import cn.iocoder.yudao.module.llm.service.http.ModelService;
import cn.iocoder.yudao.module.llm.service.modelassesstaskauto.ModelAssessTaskAutoService;
import cn.iocoder.yudao.module.llm.service.modelassesstaskmanual.ModelAssessTaskManualService;
import cn.iocoder.yudao.module.llm.service.modelassesstaskmanualbackup.ModelAssessTaskManualBackupService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.llm.enums.ErrorCodeConstants.MODEL_SERVICE_NOT_EXISTS;
import static cn.iocoder.yudao.module.llm.enums.ErrorCodeConstants.MODEL_SERVIC_ENAME_NOT_EXISTS;

/**
 * 模型服务 Service 实现类
 *
 * @author 华大大模型
 */
@Service
@Validated
public class ModelServiceServiceImpl implements ModelServiceService {

    @Resource
    private ModelServiceMapper modelServiceMapper;

    @Resource
    private AsyncModelServiceService asyncModelServiceService;

    @Resource
    private FineTuningTaskMapper fineTuningTaskMapper;

    @Resource
    private LLMBackendProperties llmBackendProperties;

    @Resource
    private ModelService modelService;

    @Lazy
    @Resource
    private ApplicationService applicationService;

    @Resource
    private ModelAssessTaskManualService modelAssessTaskManualService;

    @Resource
    private ModelAssessTaskAutoService modelAssessTaskAutoService;

    @Resource
    private ModelAssessTaskManualBackupService modelAssessTaskManualBackupService;


    @Override
    public Long createModelService(ModelServiceSaveReqVO createReqVO) {
        LambdaQueryWrapper<ModelServiceDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ModelServiceDO::getFineTuningTask,createReqVO.getFineTuningTask());
        List<ModelServiceDO> modelServiceDOS = modelServiceMapper.selectList(queryWrapper);
        if(modelServiceDOS.size() > 0){
            throw exception(new ErrorCode(10003_001, "该微调任务已生成过模型服务，不可再生成"));

        }
        // 插入
        validateModelServiceNameExists(createReqVO);
        ModelServiceDO modelService = BeanUtils.toBean(createReqVO, ModelServiceDO.class);

        FineTuningTaskDO fineTuningTaskDO = fineTuningTaskMapper.selectById(createReqVO.getFineTuningTask());

        if (fineTuningTaskDO != null){
            //aigc模型列表中的id 以及 对话用的modelName
            modelService.setJobId(fineTuningTaskDO.getJobModelListId());
            modelService.setBaseModelName(fineTuningTaskDO.getJobModelName());

        }

        // 插入
        String apikey = getApikey();
        modelService.setApiKey(apikey);
        String replace = llmBackendProperties.getModelServiceApi().replace("apiKey", apikey);
        modelService.setApiUrl(replace);

        modelService.setStatus(0);
        modelServiceMapper.insert(modelService);
//        asyncModelServiceService.createModelService(modelService);
        // 返回
        return modelService.getId();
    }

    public String getApikey() {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 30; i++) {
            // 生成一个随机的大小写字母
            char c = (char) (random.nextBoolean() ? // 随机选择大小写
                    'A' + random.nextInt(26) : // 生成大写字母
                    'a' + random.nextInt(26)); // 生成小写字母
            sb.append(c);
        }
        Long count = modelServiceMapper.selectCount(new LambdaQueryWrapper<ModelServiceDO>()
                .eq(ModelServiceDO::getApiKey, sb.toString()));
        if (count > 0) {
            getApikey();
        }
        return sb.toString();
    }

    @Override
    public void updateModelService(ModelServiceSaveReqVO updateReqVO) {
        // 校验存在
        validateModelServiceExists(updateReqVO.getId());
        validateModelServiceNameExists(updateReqVO);
        // 更新
        ModelServiceDO updateObj = BeanUtils.toBean(updateReqVO, ModelServiceDO.class);
        modelServiceMapper.updateById(updateObj);
    }

    @Override
    public void deleteModelService(Long id) {
        // 校验存在
        validateModelServiceExists(id);
        // 校验使用
        validateModelUse(id);
        // 删除
        modelServiceMapper.deleteById(id);
    }

    /**
     * 校验模型使用情况
     *
     * @param id 模型ID
     */
    private void validateModelUse (Long id) {
        ModelServiceDO modelDO = modelServiceMapper.selectById(id);
        String modelName = modelDO.getServiceName();

        // 校验 基座模型 是否在 应用中心 有使用
        validateModelUsesInApplicationCenter(id, modelName);
        // TODO: 2.7 因为使用完成再删除，页面会显现为空，所以暂时全部校验
        // 校验 基座模型 是否在 模型评估任务-人工 有使用 （是否为进行中）
        validateModelUsesInModelAssessTaskManual(id, modelName);
        // 校验 基座模型 是否在 模型评估任务-自动 有使用 （是否为进行中、推理中）
        validateModelUsesInModelAssessTaskAuto(id, modelName);
        // 校验 基座模型 是否在 模型评估任务备份-人工 有使用
        validateModelUsesInModelAssessTaskBackupManual(id, modelName);
    }

    /**
     * 校验模型是否在 应用中心 有使用
     *
     * @param id        模型ID
     * @param modelName 模型名称
     */
    private void validateModelUsesInApplicationCenter (Long id, String modelName) {
        Map<Long, String> application = applicationService.getApplicationByModelServiceId(id);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(application)) {
            String msg = String.format("模型【%s】在应用中心 %s 有使用，请先取消使用", modelName, application.values());
            throw exception(new ErrorCode(10003_001, msg));
        }
    }

    /**
     * 校验模型是否在 模型评估任务-人工 有使用
     *
     * @param id        模型ID
     * @param modelName 模型名称
     */
    private void validateModelUsesInModelAssessTaskManual (Long id, String modelName) {
        Map<Long, String> modelAssessmentTask = modelAssessTaskManualService.getModelAssessmentTaskByModelServiceId(id);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(modelAssessmentTask)) {
            String msg = String.format("模型【%s】在模型评估-人工评估 %s 有正在进行的任务，请先结束任务", modelName, modelAssessmentTask.values());
            throw exception(new ErrorCode(10003_002, msg));
        }
    }

    /**
     * 校验模型是否在 模型评估任务-自动 有使用
     *
     * @param id        模型ID
     * @param modelName 模型名称
     */
    private void validateModelUsesInModelAssessTaskAuto (Long id, String modelName) {
        Map<Long, String> modelAssessmentTask = modelAssessTaskAutoService.getModelAssessmentTaskByModelServiceId(id);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(modelAssessmentTask)) {
            String msg = String.format("模型【%s】在模型评估-自动评估 %s 有正在进行的任务，请先结束任务", modelName, modelAssessmentTask.values());
            throw exception(new ErrorCode(10003_003, msg));
        }
    }

    /**
     * 校验模型是否在 模型评估任务备份-人工 有使用
     *
     * @param id        模型ID
     * @param modelName 模型名称
     */
    private void validateModelUsesInModelAssessTaskBackupManual (Long id, String modelName) {
        Map<Long, String> modelAssessmentTask = modelAssessTaskManualBackupService.getModelAssessmentTaskByModelServiceId(id);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(modelAssessmentTask)) {
            String msg = String.format("模型【%s】在模型评估-人工评估 %s 存在备份，请先取消备份", modelName, modelAssessmentTask.values());
            throw exception(new ErrorCode(10003_004, msg));
        }
    }

    private void validateModelServiceExists(Long id) {
        if (modelServiceMapper.selectById(id) == null) {
            throw exception(MODEL_SERVICE_NOT_EXISTS);
        }
    }
    private void validateModelServiceNameExists(ModelServiceSaveReqVO updateReqVO) {
        LambdaQueryWrapper<ModelServiceDO> wrapper = new LambdaQueryWrapper<ModelServiceDO>()
                .eq(ModelServiceDO::getServiceName, updateReqVO.getServiceName());

        if (updateReqVO.getId() != null){
            wrapper.ne(ModelServiceDO::getId, updateReqVO.getId());
        }
        List<ModelServiceDO> modelServiceDOS = modelServiceMapper.selectList(wrapper);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(modelServiceDOS)){
            throw exception(MODEL_SERVIC_ENAME_NOT_EXISTS);
        }
    }

    @Override
    public ModelServiceDO getModelService(Long id) {
        return modelServiceMapper.selectById(id);
    }

    @Override
    public PageResult<ModelServiceDO> getModelServicePage(ModelServicePageReqVO pageReqVO) {
        return modelServiceMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ModelServiceDO> getModelServiceList() {
        LambdaQueryWrapper<ModelServiceDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ModelServiceDO::getStatus,2);
        return modelServiceMapper.selectList(queryWrapper);
    }

    @Override
    public void active(ModelServiceSaveReqVO updateReqVO) {
        ModelServiceDO updateObj = BeanUtils.toBean(updateReqVO, ModelServiceDO.class);
        updateObj.setStatus(1);
        modelServiceMapper.updateById(updateObj);

        //todo 开启模型服务
        asyncModelServiceService.startModelService(updateObj);
    }

    @Override
    public void unactive(ModelServiceSaveReqVO updateReqVO) {
        ModelServiceDO updateObj = BeanUtils.toBean(updateReqVO, ModelServiceDO.class);
        updateObj.setStatus(0);
        modelServiceMapper.updateById(updateObj);

        //todo 关闭模型服务
        asyncModelServiceService.stopModelService(updateObj);


    }

    @Override
    public PageResult<ModelServiceRespVO> getModelServicePage1(ModelServicePageReqVO pageReqVO) {
        PageResult<ModelServiceDO> pageResult = modelServiceMapper.selectPage(pageReqVO);
        PageResult<ModelServiceRespVO> respVo = BeanUtils.toBean(pageResult, ModelServiceRespVO.class);
        if (!CollectionUtils.isAnyEmpty(pageResult.getList())){
            List<Long> ids = pageResult.getList().stream()
                    .map(ModelServiceDO::getFineTuningTask)
                    .collect(Collectors.toList());
            List<FineTuningTaskDO> fineTuningTaskDOS = fineTuningTaskMapper.selectBatchIds(ids);
            Map<Long, FineTuningTaskDO> fineTuningTaskMap = CollectionUtils.convertMap(fineTuningTaskDOS, FineTuningTaskDO::getId);
            respVo.getList().forEach(item->{
                FineTuningTaskDO fineTuningTaskDO = fineTuningTaskMap.get(item.getFineTuningTask());
                if(fineTuningTaskDO != null){
                    item.setFineTuningTaskName(fineTuningTaskDO.getTaskName());
                }
            });
        }
        return respVo;
    }

    @Override
    public ModelServiceDO getByApiKey(String apiKey) {
        LambdaQueryWrapper<ModelServiceDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ModelServiceDO::getApiKey,apiKey);
        return  modelServiceMapper.selectOne(queryWrapper);
    }

    @Override
    public List<String> getDownLoadList(Long id) {
        ModelServiceDO modelServiceDO = modelServiceMapper.selectById(id);
        String baseModelName = modelServiceDO.getBaseModelName();
        List<String> fileList = modelService.getFileList(baseModelName);
        String modelFileDownload = llmBackendProperties.getModelFileDownload();
        List<String> res = new ArrayList<>();
        if (fileList != null){
            for (String fileName : fileList) {
                res.add(modelFileDownload + baseModelName +"/" + fileName);
            }
        }
        return res;
    }

    /**
     * 获取模型服务管理数量
     *
     * @return 模型服务管理数量
     */
    @Override
    public Long getCount () {
        return modelServiceMapper.selectCount(null);
    }

    /**
     * 根据 微调任务 id 获取 模型服务
     *
     * @param taskId 知识库 id
     * @return 模型服务的 Map 集合
     */
    @Override
    public Map<Long, String> getModelServiceByTaskId (Long taskId) {
        if (taskId != null) {
            List<ModelServiceDO> modelServiceDOS = modelServiceMapper.selectList(new LambdaQueryWrapper<ModelServiceDO>()
                    .eq(ModelServiceDO::getFineTuningTask, taskId));
            if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(modelServiceDOS)) {
                return modelServiceDOS.stream().collect(Collectors.toMap(ModelServiceDO::getId, ModelServiceDO::getServiceName));
            }
        }
        return Collections.emptyMap();
    }

}
