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

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.llm.controller.admin.prompttemplates.vo.AbilityFramework;
import cn.iocoder.yudao.module.llm.controller.admin.prompttemplates.vo.BriefFramework;
import cn.iocoder.yudao.module.llm.controller.admin.prompttemplates.vo.SampleFramework;
import cn.iocoder.yudao.module.llm.controller.admin.prompttemplates.vo.SampleFrameworkItem;
import cn.iocoder.yudao.module.llm.controller.admin.prompttemplatesbackup.vo.PromptTemplatesBackupPageReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.prompttemplatesbackup.vo.PromptTemplatesBackupRespVO;
import cn.iocoder.yudao.module.llm.controller.admin.prompttemplatesbackup.vo.PromptTemplatesBackupSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.prompttemplates.PromptTemplatesDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.prompttemplatesapplications.PromptTemplatesApplicationsDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.prompttemplatesapplicationsbackup.PromptTemplatesApplicationsBackupDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.prompttemplatesbackup.PromptTemplatesBackupDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.prompttemplatestags.PromptTemplatesTagsDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.prompttemplatestagsbackup.PromptTemplatesTagsBackupDO;
import cn.iocoder.yudao.module.llm.dal.mysql.prompttemplates.PromptTemplatesMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.prompttemplatesapplications.PromptTemplatesApplicationsMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.prompttemplatesapplicationsbackup.PromptTemplatesApplicationsBackupMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.prompttemplatesbackup.PromptTemplatesBackupMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.prompttemplatestags.PromptTemplatesTagsMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.prompttemplatestagsbackup.PromptTemplatesTagsBackupMapper;
import cn.iocoder.yudao.module.llm.service.application.ApplicationService;
import cn.iocoder.yudao.module.llm.service.label.LabelService;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
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.PROMPT_TEMPLATESBACKUP_EXISTS;
import static cn.iocoder.yudao.module.llm.enums.ErrorCodeConstants.PROMPT_TEMPLATES_BACKUP_NOT_EXISTS;

/**
 * Prompt模板备份 Service 实现类
 *
 * @author 华大大模型
 */
@Service
@Validated
public class PromptTemplatesBackupServiceImpl implements PromptTemplatesBackupService {

    @Resource
    private PromptTemplatesMapper promptTemplatesMapper;
    @Resource
    private PromptTemplatesBackupMapper promptTemplatesBackupMapper;
    @Resource
    private PromptTemplatesTagsMapper promptTemplatesTagsMapper;
    @Resource
    private PromptTemplatesApplicationsMapper promptTemplatesApplicationsMapper;
    @Resource
    private PromptTemplatesTagsBackupMapper promptTemplatesTagsBackupMapper;
    @Resource
    private PromptTemplatesApplicationsBackupMapper promptTemplatesApplicationsBackupMapper;
    @Resource
    private DictDataApi dictDataApi;
    @Resource
    private LabelService labelService;
    @Resource
    private ApplicationService applicationService;

    @Override
    public Long createPromptTemplatesBackup (PromptTemplatesBackupSaveReqVO createReqVO) {
        // 插入
        PromptTemplatesBackupDO promptTemplatesBackup = BeanUtils.toBean(createReqVO, PromptTemplatesBackupDO.class);
        promptTemplatesBackupMapper.insert(promptTemplatesBackup);

        Long srcId = createReqVO.getSrcId();

        LambdaQueryWrapper<PromptTemplatesTagsDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PromptTemplatesTagsDO::getPromptTemplateId, srcId);
        List<PromptTemplatesTagsDO> promptTemplatesTagsDOS = promptTemplatesTagsMapper.selectList(queryWrapper);
        for (PromptTemplatesTagsDO promptTemplatesTagsDO : promptTemplatesTagsDOS) {
            PromptTemplatesTagsBackupDO tagsBackupDO = new PromptTemplatesTagsBackupDO();
            tagsBackupDO.setTagId(promptTemplatesTagsDO.getTagId());
            tagsBackupDO.setPromptTemplateId(promptTemplatesBackup.getId());
            promptTemplatesTagsBackupMapper.insert(tagsBackupDO);
        }

        LambdaQueryWrapper<PromptTemplatesApplicationsDO> query = new LambdaQueryWrapper<>();
        query.eq(PromptTemplatesApplicationsDO::getPromptTemplateId, srcId);
        List<PromptTemplatesApplicationsDO> promptTemplatesApplicationsDOS = promptTemplatesApplicationsMapper.selectList(query);
        for (PromptTemplatesApplicationsDO promptTemplatesApplicationsDO : promptTemplatesApplicationsDOS) {
            PromptTemplatesApplicationsBackupDO applicationsBackupDO = new PromptTemplatesApplicationsBackupDO();
            applicationsBackupDO.setApplicationId(promptTemplatesApplicationsDO.getApplicationId());
            applicationsBackupDO.setPromptTemplateId(promptTemplatesBackup.getId());
            promptTemplatesApplicationsBackupMapper.insert(applicationsBackupDO);
        }
        // 返回
        return promptTemplatesBackup.getId();
    }

    @Override
    public void updatePromptTemplatesBackup (PromptTemplatesBackupSaveReqVO updateReqVO) {
        // 校验存在
        validatePromptTemplatesBackupExists(updateReqVO.getId());
        // 更新
        PromptTemplatesBackupDO updateObj = BeanUtils.toBean(updateReqVO, PromptTemplatesBackupDO.class);
        promptTemplatesBackupMapper.updateById(updateObj);
    }

    @Override
    public void deletePromptTemplatesBackup (Long id) {
        // 校验存在
        validatePromptTemplatesBackupExists(id);
        // 删除
        promptTemplatesBackupMapper.deleteById(id);

        LambdaQueryWrapper<PromptTemplatesTagsBackupDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper.eq(PromptTemplatesTagsBackupDO::getPromptTemplateId, id);
        promptTemplatesTagsBackupMapper.delete(wrapper);


        LambdaQueryWrapper<PromptTemplatesApplicationsBackupDO> wrapper1 = new LambdaQueryWrapperX<>();
        wrapper1.eq(PromptTemplatesApplicationsBackupDO::getPromptTemplateId, id);
        promptTemplatesApplicationsBackupMapper.delete(wrapper1);
    }

    private void validatePromptTemplatesBackupExists (Long id) {
        if (promptTemplatesBackupMapper.selectById(id) == null) {
            throw exception(PROMPT_TEMPLATES_BACKUP_NOT_EXISTS);
        }
    }

    @Override
    public PromptTemplatesBackupRespVO getPromptTemplatesBackup (Long id) {
        PromptTemplatesBackupDO templatesDO = this.promptTemplatesBackupMapper.selectById(id);

        if (templatesDO == null) {
            throw exception(PROMPT_TEMPLATES_BACKUP_NOT_EXISTS);
        }

        PromptTemplatesBackupRespVO promptTemplates = BeanUtils.toBean(templatesDO, PromptTemplatesBackupRespVO.class);

        // 标签
        getPromptTemplatesLabelResult(id, promptTemplates);

        // 应用
        getPromptTemplatesApplicationsResult(id, promptTemplates);

        return promptTemplates;
    }

    /**
     * 标签
     *
     * @param id              模版ID
     * @param promptTemplates 模版
     */
    private void getPromptTemplatesLabelResult (Long id, PromptTemplatesBackupRespVO promptTemplates) {
        // 标签
        List<PromptTemplatesTagsBackupDO> tagDOList = this.promptTemplatesTagsBackupMapper
                .selectList("prompt_template_id", id);

        Map<Long, String> labelMap = labelService.getLabelMap(true);

        if (CollectionUtils.isNotEmpty(tagDOList)) {
            // 过滤 tagDOList 在 labelMap 中不存在的 tagIds，只保留存在的
            List<String> tagIds = tagDOList.stream()
                    .filter(tagsDO -> labelMap.containsKey(tagsDO.getTagId()))
                    .map(p -> String.valueOf(p.getTagId()))
                    .collect(Collectors.toList());
            promptTemplates.setTagIds(tagIds);

            // 获取对应的标签名称
            List<String> labelNameList = tagIds.stream()
                    .map(tagId -> labelMap.computeIfAbsent(Long.parseLong(tagId), k -> null))
                    .collect(Collectors.toList());
            promptTemplates.setTagNames(labelNameList);
        }
    }

    /**
     * 应用
     *
     * @param id              模版ID
     * @param promptTemplates 模版
     */
    private void getPromptTemplatesApplicationsResult (Long id, PromptTemplatesBackupRespVO promptTemplates) {
        // 获取当前模版的应用
        List<PromptTemplatesApplicationsBackupDO> applicationDOList = this.promptTemplatesApplicationsBackupMapper
                .selectList("prompt_template_id", id);

        Map<Long, String> appMap = applicationService.getApplicatioMap();

        if (CollectionUtils.isNotEmpty(applicationDOList)) {
            // 过滤 applicationDOList 在 appMap 中不存在的 applicationIds，只保留存在的
            List<String> applicationIds = applicationDOList.stream()
                    .filter(applicationDO -> appMap.containsKey(applicationDO.getApplicationId()))
                    .map(p -> p.getApplicationId().toString())
                    .collect(Collectors.toList());
            promptTemplates.setApplicationIds(applicationIds);

            // 获取对应的应用名称
            List<String> appNameList = applicationIds.stream()
                    .map(appId -> appMap.computeIfAbsent(Long.parseLong(appId), k -> null))
                    .collect(Collectors.toList());
            promptTemplates.setApplicationNames(appNameList);
        }
    }

    @Override
    public PageResult<PromptTemplatesBackupRespVO> getPromptTemplatesBackupPage (PromptTemplatesBackupPageReqVO pageReqVO) {
        PageResult<PromptTemplatesBackupDO> pageDoList = this.promptTemplatesBackupMapper.selectPage(pageReqVO);
        PageResult<PromptTemplatesBackupRespVO> pageRespList = BeanUtils.toBean(pageDoList, PromptTemplatesBackupRespVO.class);
        List<PromptTemplatesBackupRespVO> templatesRespList = pageRespList.getList();


        for (PromptTemplatesBackupRespVO respVO : templatesRespList) {
            // TODO 使用量查询暂时设置为0
            respVO.setUsedCount(0);
            try {
                List<PromptTemplatesTagsBackupDO> tagDOList = this.promptTemplatesTagsBackupMapper
                        .selectList("prompt_template_id", respVO.getId());

                // 标签
                Map<Long, String> labelMap = labelService.getLabelMap(true);

                if (CollectionUtils.isNotEmpty(tagDOList)) {
                    // 过滤 tagDOList 在 labelMap 中不存在的 tagIds，只保留存在的
                    List<String> tagIds = tagDOList.stream()
                            .filter(tagsDO -> labelMap.containsKey(tagsDO.getTagId()))
                            .map(p -> String.valueOf(p.getTagId()))
                            .collect(Collectors.toList());
                    respVO.setTagIds(tagIds);

                    // 获取对应的标签名称
                    List<String> labelNameList = tagIds.stream()
                            .map(tagId -> labelMap.computeIfAbsent(Long.parseLong(tagId), k -> null))
                            .collect(Collectors.toList());
                    respVO.setTagNames(labelNameList);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                // 获取当前模版的应用
                List<PromptTemplatesApplicationsBackupDO> applicationDOList = this.promptTemplatesApplicationsBackupMapper
                        .selectList("prompt_template_id", respVO.getId());

                Map<Long, String> appMap = applicationService.getApplicatioMap();

                if (CollectionUtils.isNotEmpty(applicationDOList)) {
                    // 过滤 applicationDOList 在 appMap 中不存在的 applicationIds，只保留存在的
                    List<String> applicationIds = applicationDOList.stream()
                            .filter(applicationDO -> appMap.containsKey(applicationDO.getApplicationId()))
                            .map(p -> p.getApplicationId().toString())
                            .collect(Collectors.toList());
                    respVO.setApplicationIds(applicationIds);

                    // 获取对应的应用名称
                    List<String> appNameList = applicationIds.stream()
                            .map(appId -> appMap.computeIfAbsent(Long.parseLong(appId), k -> null))
                            .collect(Collectors.toList());
                    respVO.setApplicationNames(appNameList);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            StringBuilder append = new StringBuilder();
            String categoryName = this.dictDataApi.getDictDataLabel("llm_prompt_template_framework",Integer.valueOf(respVO
                    .getTemplateFramework()));
            switch (categoryName) {
                case "简介框架":
                    BriefFramework briefFramework = JSONObject.parseObject(respVO.getTemplateText(), BriefFramework.class);
                    respVO.setBriefFramework(briefFramework);
                    StringBuilder stringBuilder = new StringBuilder();
                    if(StringUtils.isNotBlank(briefFramework.getOrderInfo())){
                        stringBuilder.append("指令:").append(briefFramework.getOrderInfo()).append("/n");
                    }

                    if(StringUtils.isNotBlank(briefFramework.getBgInfo())){
                        stringBuilder.append("背景信息:").append(briefFramework.getBgInfo()).append("/n");
                    }

                    if(StringUtils.isNotBlank(briefFramework.getPlusInfo())){
                        stringBuilder.append("补充数据:").append(briefFramework.getPlusInfo()).append("/n");
                    }

                    if(StringUtils.isNotBlank(briefFramework.getOutputFormat())){
                        stringBuilder.append("输出格式:").append(briefFramework.getOutputFormat()).append("/n");
                    }

                    append = new StringBuilder(stringBuilder.toString());
                    break;
                case "角色能力框架":
                    AbilityFramework abilityFramework = JSONObject.parseObject(respVO.getTemplateText(), AbilityFramework.class);
                    respVO.setAbilityFramework(abilityFramework);
                    StringBuilder stringBuilder1 = new StringBuilder();
                    if(StringUtils.isNotBlank(abilityFramework.getOrderInfo())){
                        stringBuilder1.append("指令:").append(abilityFramework.getOrderInfo()).append("/n");
                    }

                    if(StringUtils.isNotBlank(abilityFramework.getBgInfo())){
                        stringBuilder1.append("背景信息:").append(abilityFramework.getBgInfo()).append("/n");
                    }

                    if(StringUtils.isNotBlank(abilityFramework.getAbilityInfo())){
                        stringBuilder1.append("能力与角色:").append(abilityFramework.getAbilityInfo()).append("/n");
                    }

                    if(StringUtils.isNotBlank(abilityFramework.getOutputFormat())){
                        stringBuilder1.append("输出格式:").append(abilityFramework.getOutputFormat()).append("/n");
                    }

                    append = new StringBuilder(stringBuilder1.toString());

                    break;
                case "样例提示框架":
                    SampleFramework sampleFramework = JSONObject.parseObject(respVO.getTemplateText(), SampleFramework.class);
                    respVO.setSampleFramework(sampleFramework);

                    if(StringUtils.isNotBlank(sampleFramework.getBgInfo())){
                        append = new StringBuilder("背景信息" + sampleFramework.getBgInfo() + "/n" +
                                                   "样例列表:" + "/n");
                    }

                    if(sampleFramework.getItemList() != null && !sampleFramework.getItemList().isEmpty()){
                        for (SampleFrameworkItem sampleFrameworkItem : sampleFramework.getItemList()) {
                            append.append("输入:").append(sampleFrameworkItem.getInput()).append(",").append("输出:").append(sampleFrameworkItem.getOutput()).append("/n");
                        }
                    }

                    break;
                default:
                    append = new StringBuilder(respVO.getTemplateText());
                    break;
            }
            respVO.setTemplateText(append.toString());
        }
        return pageRespList;
    }

    @Override
    public void isBackup (Long srcId) {
        List<PromptTemplatesBackupDO> templateBackupDOList = this.promptTemplatesBackupMapper.selectList("src_id", srcId);
        if (templateBackupDOList != null && !templateBackupDOList.isEmpty()) {
            throw exception(PROMPT_TEMPLATESBACKUP_EXISTS);
        }
    }

    @Override
    public PromptTemplatesBackupDO getPromptTemplatesBackupBySrcId (Long srcId) {
        List<PromptTemplatesBackupDO> templateBackupDOList = this.promptTemplatesBackupMapper.selectList("src_id", srcId);
        if (templateBackupDOList == null || templateBackupDOList.isEmpty()) {
            return null;
        }
        return templateBackupDOList.get(0);
    }

    @Override
    public void unbackupPromptTemplates (PromptTemplatesBackupSaveReqVO updateReqVO) {
        Long srcId = updateReqVO.getSrcId();
        PromptTemplatesDO promptTemplatesDO = new PromptTemplatesDO();
        promptTemplatesDO.setId(srcId);
        promptTemplatesDO.setBackupId(0l);
        promptTemplatesMapper.updateById(promptTemplatesDO);

        Long id = updateReqVO.getId();
        this.deletePromptTemplatesBackup(id);

    }

    /**
     * 根据 标签id 获取 模版备份
     *
     * @param labelId 标签id
     * @return 模版备份
     */
    @Override
    public Map<Long, String> getPromptTemplateBackByLabelId (Long labelId) {
        if (labelId == null) {
            return Collections.emptyMap();
        }

        List<PromptTemplatesBackupDO> templatesDO = this.promptTemplatesBackupMapper.getPromptTemplateBackByLabelId(labelId);
        if (CollectionUtils.isEmpty(templatesDO)) {
            return Collections.emptyMap();
        }

        return templatesDO.stream().collect(Collectors.toMap(PromptTemplatesBackupDO::getId, PromptTemplatesBackupDO::getName));
    }

    /**
     * 根据 应用id 获取 模版备份
     *
     * @param applicationId 应用id
     * @return 模版备份
     */
    @Override
    public Map<Long, String> getPromptTemplateBackByAppId (Long applicationId) {
        if (applicationId == null) {
            return Collections.emptyMap();
        }

        List<PromptTemplatesBackupDO> templatesDO = this.promptTemplatesBackupMapper.getPromptTemplateBackByAppId(applicationId);
        if (CollectionUtils.isEmpty(templatesDO)) {
            return Collections.emptyMap();
        }

        return templatesDO.stream().collect(Collectors.toMap(PromptTemplatesBackupDO::getId, PromptTemplatesBackupDO::getName));
    }

}
