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

import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.llm.controller.admin.label.vo.LabelPageReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.label.vo.LabelSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.label.LabelDO;
import cn.iocoder.yudao.module.llm.dal.mysql.label.LabelMapper;
import cn.iocoder.yudao.module.llm.service.application.ApplicationService;
import cn.iocoder.yudao.module.llm.service.prompttemplates.PromptTemplatesService;
import cn.iocoder.yudao.module.llm.service.prompttemplatesbackup.PromptTemplatesBackupService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
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.LABEL_NAME_EXISTS;
import static cn.iocoder.yudao.module.llm.enums.ErrorCodeConstants.LABEL_NOT_EXISTS;

/**
 * 标签管理 Service 实现类
 *
 * @author 华大大模型
 */
@Service
@Validated
public class LabelServiceImpl implements LabelService {

    @Resource
    private LabelMapper labelMapper;

    @Resource
    private ApplicationService applicationService;

    @Lazy
    @Resource
    private PromptTemplatesService promptTemplatesService;

    @Lazy
    @Resource
    private PromptTemplatesBackupService promptTemplatesBackupService;

    @Override
    public Long createLabel (LabelSaveReqVO createReqVO) {
        validateLabelNameExists(createReqVO);
        // 插入
        LabelDO label = BeanUtils.toBean(createReqVO, LabelDO.class);
        labelMapper.insert(label);
        // 返回
        return label.getId();
    }

    @Override
    public void updateLabel (LabelSaveReqVO updateReqVO) {
        // 校验存在
        validateLabelExists(updateReqVO.getId());
        validateLabelNameExists(updateReqVO);
        // 校验是否启用状态从启用变为停用
        checkIfLabelEnabledToDisabled(updateReqVO);
        // 更新
        LabelDO updateObj = BeanUtils.toBean(updateReqVO, LabelDO.class);
        labelMapper.updateById(updateObj);
    }

    /**
     * 检查是否启用状态从启用变为停用
     *
     * @param updateRequestVO 标签修改
     */
    private void checkIfLabelEnabledToDisabled (LabelSaveReqVO updateRequestVO) {
        Long id = updateRequestVO.getId();
        // 获取标签信息
        LabelDO labelDO = labelMapper.selectById(id);
        // 检查标签状态是否从启用变为停用
        if (labelDO.getStatus() == 0) {
            if (updateRequestVO.getStatus() == 1) {
                // 验证标签使用情况
                validateLabelUse(labelDO);
            }
        }
    }

    /**
     * 校验标签使用情况
     *
     * @param label 标签对象
     */
    private void validateLabelUse (LabelDO label) {
        Long id = label.getId();
        String labelName = label.getLabelName();

        // 检查标签是否在 应用中心 有使用
        validateLabelUsesInApplicationCenter(id, labelName);
        // 检查标签是否在 Prompt 模版中有使用
        validateLabelUsesInPromptTemplate(id, labelName);
        // 检查标签是否在 Prompt 模版备份中有使用
        validateLabelUsesInPromptTemplateBackup(id, labelName);
    }

    /**
     * 检查标签是否在 应用中心 有使用
     *
     * @param id   标签id
     * @param name 标签名称
     */
    private void validateLabelUsesInApplicationCenter (Long id, String name) {
        Map<Long, String> application = applicationService.getApplicationByLabelId(id);
        if (CollectionUtils.isNotEmpty(application)) {
            String msg = String.format("标签【%s】在应用中心 %s 有使用，请先删除应用中心中的标签", name, application.values());
            throw exception(new ErrorCode(10004_001, msg));
        }
    }

    /**
     * 检查标签是否在 Prompt模版 有使用
     *
     * @param id   标签id
     * @param name 标签名称
     */
    private void validateLabelUsesInPromptTemplate (Long id, String name) {
        Map<Long, String> template = promptTemplatesService.getPromptTemplateByLabelId(id);
        if (CollectionUtils.isNotEmpty(template)) {
            String msg = String.format("标签【%s】在 Prompt模版 %s 有使用，请先删除Prompt模版中的标签", name, template.values());
            throw exception(new ErrorCode(10004_002, msg));
        }
    }

    /**
     * 检查标签是否在 Prompt模版备份 有使用
     *
     * @param id   标签id
     * @param name 标签名称
     */
    private void validateLabelUsesInPromptTemplateBackup (Long id, String name) {
        Map<Long, String> template = promptTemplatesBackupService.getPromptTemplateBackByLabelId(id);
        if (CollectionUtils.isNotEmpty(template)) {
            String msg = String.format("标签【%s】在 Prompt模版备份 %s 有使用，请先取消Prompt模版备份", name, template.values());
            throw exception(new ErrorCode(10004_003, msg));
        }
    }

    @Override
    public void deleteLabel (Long id) {
        // 校验存在
        validateLabelExists(id);
        // 获取标签信息
        LabelDO labelDO = labelMapper.selectById(id);
        // 验证标签使用情况
        validateLabelUse(labelDO);
        // 删除
        labelMapper.deleteById(id);
    }

    private void validateLabelExists (Long id) {
        if (labelMapper.selectById(id) == null) {
            throw exception(LABEL_NOT_EXISTS);
        }
    }

    private void validateLabelNameExists (LabelSaveReqVO updateReqVO) {
        LambdaQueryWrapper<LabelDO> wrapper = new LambdaQueryWrapper<LabelDO>()
                .eq(LabelDO::getLabelName, updateReqVO.getLabelName());

        if (updateReqVO.getId() != null) {
            wrapper.ne(LabelDO::getId, updateReqVO.getId());
        }
        List<LabelDO> labelDOS = labelMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(labelDOS)) {
            throw exception(LABEL_NAME_EXISTS);
        }
    }

    @Override
    public LabelDO getLabel (Long id) {
        return labelMapper.selectById(id);
    }

    @Override
    public PageResult<LabelDO> getLabelPage (LabelPageReqVO pageReqVO) {
        return labelMapper.selectPage(pageReqVO);
    }

    @Override
    public List<LabelDO> getLabelList () {
        List<LabelDO> result = labelMapper.selectList();
        if (result == null) {
            return new ArrayList<>();
        }
        return result;
    }

    /**
     * 获取标签Map
     *
     * @param allLabel 是否获取所有标签 true:获取所有标签 false:获取已启用标签
     * @return 标签列表
     */
    @Override
    public Map<Long, String> getLabelMap (boolean allLabel) {
        List<LabelDO> labels = labelMapper.selectList();
        if (CollectionUtils.isEmpty(labels)) {
            return Collections.emptyMap();
        }

        if (allLabel) {
            return labels.stream().collect(Collectors.toMap(LabelDO::getId, LabelDO::getLabelName));
        } else {
            List<LabelDO> enableLabels = labels.stream().filter(labelDO -> labelDO.getStatus() == 0).collect(Collectors.toList());
            return enableLabels.stream().collect(Collectors.toMap(LabelDO::getId, LabelDO::getLabelName));
        }
    }

    /**
     * 获取所有已开启的标签
     *
     * @return 标签列表
     */
    @Override
    public List<LabelDO> getEnableLabelList () {
        List<LabelDO> labels = labelMapper.selectList();
        if (CollectionUtils.isEmpty(labels)) {
            return Collections.emptyList();
        }

        // status 0: 启用，1: 停用
        return labels.stream().filter(labelDO -> labelDO.getStatus() == 0).collect(Collectors.toList());
    }

}
