package com.kexue.skills.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kexue.skills.common.Assert;
import com.kexue.skills.common.util.HttpUtil;
import com.kexue.skills.config.DeepSeekConfig;
import com.kexue.skills.config.GlmConfig;
import com.kexue.skills.entity.CmsContent;
import com.kexue.skills.entity.CmsTag;
import com.kexue.skills.entity.dto.CmsTagDto;
import com.kexue.skills.entity.request.SkillAnalyzeRequest;
import com.kexue.skills.entity.request.SkillGenRequest;
import com.kexue.skills.entity.request.SkillPreGenRequest;
import com.kexue.skills.entity.request.SkillRequest;
import com.kexue.skills.entity.response.SkillResponse;
import com.kexue.skills.exception.BizException;
import com.kexue.skills.mapper.CmsContentMapper;
import com.kexue.skills.service.CmsTagService;
import com.kexue.skills.service.SkillGenService;
import com.kexue.skills.utils.EscapeCharacterUtils;
import com.kexue.skills.utils.YamlToMapUtil;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.error.YAMLException;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 技能生成服务实现
 *
 * @author 维哥
 * @since 2026-01-28
 */
@Slf4j
@Service
public class SkillGenServiceImpl implements SkillGenService {

    @Autowired
    private DeepSeekConfig deepSeekConfig;
    
    @Autowired
    private GlmConfig glmConfig;
    
    @Autowired
    private CmsTagService cmsTagService;

    @Resource
    private CmsContentMapper cmsContentMapper;

    /**
     * 生成技能
     *
     * @param request 生成请求
     * @return 生成结果
     */
    @Override
    public SkillResponse preGenerate(SkillPreGenRequest request) {
        log.info("生成技能请求: {}", request);
        String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions";
        
        // 从数据库中读取cms_tag表的标签信息
        CmsTagDto tagDto = new CmsTagDto();
        tagDto.setDeleteFlag(0);
        tagDto.setStatus(1);
        List<CmsTag> tags = cmsTagService.getList(tagDto);
        
        // 将标签名称拼接成逗号分隔的字符串
        StringBuilder tagsList = new StringBuilder();
        for (int i = 0; i < tags.size(); i++) {
            CmsTag tag = tags.get(i);
            tagsList.append(tag.getTagId()+"."+tag.getTagName());
            if (i < tags.size() - 1) {
                tagsList.append("，");
            }
        }
        
        SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(), 
                deepSeekConfig.getChat().getTemperature(), deepSeekConfig.getChat().getMaxTokens(), 
                request.getPrompt(), tagsList.toString());

        String deepseekResponse = "";
        try {
            // 发送HTTP请求到deepseek API
            deepseekResponse = HttpUtil.sendPostRequest(url, skillRequest, deepSeekConfig.getApiKey(), null);
            log.info("Deepseek API响应: {}", deepseekResponse);

            // 解析deepseek返回结果
            JSONObject responseJson = JSON.parseObject(deepseekResponse);
            List<JSONObject> choices = responseJson.getJSONArray("choices").toJavaList(JSONObject.class);
            
            if (choices != null && !choices.isEmpty()) {
                // 获取最新的choice（这里是第一个，因为只有一个）
                JSONObject latestChoice = choices.get(0);
                JSONObject message = latestChoice.getJSONObject("message");
                String content = message.getString("content");
                
                // 解析content中的JSON
                JSONObject skillJson = JSON.parseObject(content);
                SkillResponse skillResponse = new SkillResponse();
                skillResponse.setName(skillJson.getString("name"));
                skillResponse.setDescription(skillJson.getString("description"));
                skillResponse.setTags(skillJson.getJSONArray("tags").toJavaList(String.class));
                
                log.info("解析技能响应: {}", skillResponse);
                return skillResponse;
            }
        } catch (Exception e) {
            log.error("调用Deepseek API失败: {}", e.getMessage(), e);
            throw new BizException("调用Deepseek API失败:"+ e.getMessage()+" Deepseek API响应:"+ deepseekResponse);
        }

        return null;
    }

    @Override
    public SkillResponse preGenerateV2(SkillPreGenRequest request) {
        log.info("生成技能请求V2: {}", request);
        String url = glmConfig.getBaseUrl() + "/chat/completions";
        String apiKey = glmConfig.getApiKey();
        String model = glmConfig.getChat().getModel();
        double temperature = glmConfig.getChat().getTemperature();
        int maxTokens = glmConfig.getChat().getMaxTokens();
        
        // 从数据库中读取cms_tag表的标签信息
        CmsTagDto tagDto = new CmsTagDto();
        tagDto.setDeleteFlag(0);
        tagDto.setStatus(1);
        List<CmsTag> tags = cmsTagService.getList(tagDto);
        
        // 将标签名称拼接成逗号分隔的字符串
        StringBuilder tagsList = new StringBuilder();
        for (int i = 0; i < tags.size(); i++) {
            CmsTag tag = tags.get(i);
            tagsList.append(tag.getTagId()+"."+tag.getTagName());
            if (i < tags.size() - 1) {
                tagsList.append("，");
            }
        }
        
        // 构建系统消息内容
        String systemContent = "你是一个专业的AI技能设计助手。请根据agent skills撰写规范，按照用户提出的主题描述及参考文件，生成这个skill的名称、描述，并从以下标签列表中选择至少3个标签：\"" + tagsList.toString() + "\"，tags只需要返回序号数组，并简述这个skill的具体价值点。输出json格式，仅输出以上所提到的名称、描述、标签、价值点，节点名称分别为name、description、tags、value_point，节点内容以中文形式返回。请严格按照指定的JSON格式输出，仅包含要求的字段，以中文形式返回。";
        
        // 准备文件URL列表
        List<String> fileUrls = new ArrayList<>();
        if (request.getFileUrl() != null && !request.getFileUrl().isEmpty()) {
            fileUrls.add(request.getFileUrl());
        }
        if (request.getFileUrls() != null && !request.getFileUrls().isEmpty()) {
            fileUrls.addAll(request.getFileUrls());
        }
        
        // 创建技能请求
        SkillRequest skillRequest = new SkillRequest(model, systemContent, request.getPrompt(), fileUrls, temperature, maxTokens);

        String response = "";
        try {
            // 发送HTTP请求到API
            response = HttpUtil.sendPostRequest(url, skillRequest, apiKey, null);
            log.info("API响应: {}", response);

            // 解析返回结果
            JSONObject responseJson = JSON.parseObject(response);
            List<JSONObject> choices = responseJson.getJSONArray("choices").toJavaList(JSONObject.class);
            
            if (choices != null && !choices.isEmpty()) {
                // 获取最新的choice（这里是第一个，因为只有一个）
                JSONObject latestChoice = choices.get(0);
                JSONObject message = latestChoice.getJSONObject("message");
                String content = message.getString("content");
                
                // 解析content中的JSON
                JSONObject skillJson = JSON.parseObject(content);
                SkillResponse skillResponse = new SkillResponse();
                skillResponse.setName(skillJson.getString("name"));
                skillResponse.setDescription(skillJson.getString("description"));
                skillResponse.setTags(skillJson.getJSONArray("tags").toJavaList(String.class));
                skillResponse.setSummary(skillJson.getString("value_point"));
                
                log.info("解析技能响应: {}", skillResponse);
                return skillResponse;
            }
        } catch (Exception e) {
            log.error("调用API失败: {}", e.getMessage(), e);
            throw new BizException("调用Deepseek API失败:"+ e.getMessage()+" Deepseek API响应:"+ response);
        }
        return null;
    }

    @Override
    public CmsContent generate(SkillGenRequest request) {
        log.info("生成技能请求: {}", request);
        // 参数验证，确保每个参数都必须传递
        Assert.notEmpty(request.getName(), "技能名称不能为空");
        Assert.notEmpty(request.getDescription(), "技能描述不能为空");
        Assert.notEmpty(request.getTags(), "技能标签不能为空");
        Assert.notEmpty(request.getRequirement(), "技能摘要不能为空");
        String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions";

        // 从数据库中读取cms_tag表的标签信息
        CmsTagDto tagDto = new CmsTagDto();
        tagDto.setDeleteFlag(0);
        tagDto.setStatus(1);
        List<CmsTag> tags = cmsTagService.getList(tagDto);

        List<String> tags1 = request.getTags();

        // 将标签名称拼接成逗号分隔的字符串
        StringBuilder tagsList = new StringBuilder();
        String defaultIcon = "";
        for (int i = 0; i < tags.size(); i++) {
            CmsTag tag = tags.get(i);
            if (tags1.contains(tag.getTagId()+"")) {
                if (StringUtil.isEmpty(defaultIcon)){
                    defaultIcon = tag.getIcon();
                }
                tagsList.append(tag.getTagName());
                if (i < tags.size() - 1) {
                    tagsList.append(",");
                }
            }
        }
        String systemContent = """
            你是AI技能包设计专家，仅输出【完整的纯YAML文本】，输出内容是完整可解析的技能YAML描述文件，绝非片段，不包含任何多余文字（无解释、无注释、无引言、无结尾）。
            
            ### 一、YAML顶层强制规则（仅一个节点：package）
            1. 顶层只能有 package 一个节点，所有信息（名称、版本、目录结构等）均嵌套在 package 下
            2. package 节点必含子字段：name、version、description、author、created、tags、structure（缺一不可）
            3. 最终必须输出完整闭合的YAML结构，禁止输出残缺片段、部分节点
            
            ### 二、package子字段规范（固定格式）
            1. name：技能名称（与用户提供的Skill名称完全一致，不修改）
            2. version：固定为 "1.0.0"
            3. description：用户提供的Skill描述（完整复制，不增删任何内容）
            4. author：固定为 "AI技能生成助手"
            5. created：格式为 "YYYY-MM-DD"（使用当前日期，如2026-04-01）
            6. tags：数组格式，值为用户提供的Skill标签（中文，自动去重，逗号后加空格）
            7. structure：技能包目录树，根目录固定为 /，structure下直接编写根目录的一级子文件/子文件夹，禁止重复描述根目录本身
            
            ### 三、structure目录树规则（仅Python脚本，无其他语言）
            #### 1. 基础必含文件（所有技能通用）
            - 根目录 / 下必生成：skills.md 文件，归属父路径 /，文件必须保留后缀名 .md
            
            #### 2. structure核心编写规则
            1. structure节点下不写根目录/的描述，直接从一级子文件/子文件夹开始编写
            2. 【path路径强制规则】path只写父级目录路径，不拼接文件名称/目录名称
               - 目录自身名称使用 name 字段体现，目录一律无后缀名
               - 文件自身名称使用 name 字段体现，文件必须保留标准后缀名
               - 示例：scripts目录在根目录下 → path: /，name: scripts
               - 示例：skills.md在根目录下 → path: /，name: skills.md
               - 示例：main.py在scripts目录下 → path: /scripts，name: main.py
            3. 所有directory/file节点均为根目录/的直接/间接子节点
            
            #### 3. Python脚本目录/文件判断逻辑
            - 若用户提供的“Skill描述”“Skill摘要”中包含“脚本”“代码”“执行”“运行”“处理”“计算”等需执行逻辑的关键词：
              1. 必须新增 scripts 目录，该目录为文件夹，无任何后缀名，path: /，name: scripts
              2. 必须在该目录下固定生成 main.py 文件，文件必须带 .py 后缀，不允许省略或修改文件名
            - 若用户需求中无任何执行逻辑相关描述（如纯文档、纯说明类技能）：不生成 scripts 目录，避免冗余
            
            #### 4. 节点必含字段
            - directory类型：name、type、path（仅父级路径）、format（固定"dir"）、description、children（空目录写 children: []）
            - file类型：name、type、path（仅父级路径）、format（仅markdown/python两种）、description、content（非空，有实际可用内容）
            
            ### 四、文件content内容规范（Python脚本必实用）
            #### 1. 根目录下 skills.md
            - # 技能名称（不加多余符号，居中可加空格但不强制）
            - ## 技能描述（整合用户“描述+摘要”，补充逻辑连贯性）
            - ## 标签（格式：- 标签1\n- 标签2）
            - ## 使用说明（分点写：适用场景、操作步骤，需脚本则写“运行scripts/main.py脚本”，无需则写“直接参考文档使用”）
            - ## 目录结构（用代码块 ``` 列出所有文件/目录路径）
            
            #### 2. scripts目录下 main.py
            - 必含依赖导入（如 import pandas as pd，无依赖则不写）
            - 必含入口函数 def execute(params: dict) -> dict:（参数为dict，返回dict结果）
            - 函数内必含：
              1. 参数校验（判断必填键是否存在，缺失返回错误）
              2. 核心逻辑（匹配技能需求，如数据处理、文本分析）
              3. 结果返回（成功：{"status": "success", "data": 结果}；失败：{"status": "fail", "error": 信息}）
            - 必含注释：函数说明、参数/返回值说明、示例调用（if __name__ == "__main__": 块）
            - 禁止空函数、语法错误，确保复制后可直接运行
            
            ### 五、YAML语法死规定（100%无解析错误）
            1. 缩进：统一2个空格（禁止Tab，禁止1/3/4空格，嵌套层级严格对齐）
               - package 下子字段缩进2空格
               - structure 下目录/文件节点缩进4空格（package→structure→children，每层+2空格）
            2. 路径：全部遵循path只写父目录规则，Unix风格 /，禁止 \\ 或 ./
            3. 字符串：特殊字符（:、#、空格）无需转义，直接书写
            4. 数组：tags格式严格为 tags: [标签1, 标签2]（逗号后加空格，无多余逗号）
            5. content：多行内容用 | 开头，内容行首顶格，内部遵循对应格式缩进（Python用4空格）
            
            ### 六、错误规避红线（绝对不能触碰）
            1. 禁止顶层出现除 package 外的任何节点
            2. 禁止在YAML前后加任何多余文字
            3. 禁止生成非Python脚本，禁止生成无后缀的脚本文件
            4. 禁止字段缺失
            5. 禁止输出YAML片段，必须输出完整可解析文件
            6. structure禁止描述根目录/，直接从一级子节点开始
            7. 严禁path中携带文件/目录名称，必须只写父级路径
            8. 严禁将scripts目录错误添加后缀名，严禁修改Python脚本名为非main.py
            
            最终输出仅完整纯YAML，直接可复制存储、解析使用，无任何冗余或格式问题！
            """;

        String userContent = """
            基于以下信息生成技能包YAML，严格遵守system指令（仅Python脚本，无其他语言）：
            1. Skill名称：%s
            2. Skill描述：%s
            3. Skill标签：%s（中文，直接使用，不修改）
            4. Skill摘要/需求：%s（用于完善skills.md的“使用说明”章节）
            """.formatted(
                request.getName(),
                request.getDescription(),
                tagsList.toString(),
                request.getRequirement()
        );
        SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(),systemContent,userContent,deepSeekConfig.getChat().getTemperature(), 8192,"text");
        String deepseekResponse = "";
        try {
            // 发送HTTP请求到deepseek API
            deepseekResponse = HttpUtil.sendPostRequest(url, skillRequest, deepSeekConfig.getApiKey(), null);
            log.info("Deepseek API响应: {}", deepseekResponse);
            JSONObject responseJson = JSON.parseObject(deepseekResponse);
            String content = responseJson.getJSONArray("choices").toJavaList(JSONObject.class).get(0).getJSONObject("message").getString("content");
            content = EscapeCharacterUtils.removeEscapeCharacters( content);//去除转义字符
            CmsContent cmsContent = getCmsContent(request, content, StpUtil.getLoginIdAsLong(),defaultIcon);
            List<CmsTag> list = tags.stream().filter(tag -> tag.getTagId() == Long.parseLong(cmsContent.getTags().split(",")[0])).toList();
            if (CollectionUtil.isNotEmpty( list)){
                cmsContent.setIcon(list.get(0).getIcon());
            }
            // 保存到数据库
            cmsContentMapper.insert(cmsContent);
            return cmsContent;
        } catch (Exception e) {
            log.error("调用Deepseek API失败: {}", e.getMessage(), e);
            throw new BizException("调用Deepseek API失败:"+ e.getMessage()+" Deepseek API响应:"+ deepseekResponse);
        }
    }

    private CmsContent getCmsContent(SkillGenRequest request, String CmsContent,Long userId,String defaultIcon){
        CmsContent cmsContent = new CmsContent();
        cmsContent.setTitle(request.getName());
        cmsContent.setDescription(request.getDescription());
        cmsContent.setContent(CmsContent);
        cmsContent.setTags(request.getTags().stream().map(String::valueOf).collect(Collectors.joining(",")));
        cmsContent.setIsPaid(0);//免费
        cmsContent.setIsOfficial(false);
        cmsContent.setPublishStatus(1);
        cmsContent.setAuthorId(userId);
        cmsContent.setAuthorName(null);
        cmsContent.setAuditStatus(1);
        cmsContent.setViewCount(0);
        cmsContent.setCommentCount(0);
        cmsContent.setRequiredPoints(0);
        cmsContent.setSupportPointsPay(0);
        cmsContent.setPrice(new BigDecimal(0));
        cmsContent.setLikeCount(0);
        cmsContent.setShareCount(0);
        cmsContent.setCreateTime(new Date());
        cmsContent.setUpdateTime(new Date());
        cmsContent.setContentType(1);
        cmsContent.setCreateBy(userId+"");
        cmsContent.setUpdateBy(userId+"");
        cmsContent.setDeleteFlag(0);
        cmsContent.setIcon(defaultIcon);
        cmsContent.setRequirement(request.getRequirement());
        cmsContent.setIntroduce(request.getIntroduce());
        return cmsContent;
    }


    /**
     * 分析技能
     *
     * @param request 分析请求
     * @return 分析结果
     */
    @Override
    public String analyzeSkill(SkillAnalyzeRequest request) {
        log.info("分析技能请求: {}", request);
        // 这里可以实现技能分析逻辑
        // 不需要数据库操作，直接返回结果
        return "技能分析成功: " + request.getSkillId();
    }

    @Override
    public String genIntroduce(String content) {
        log.info("生成技能介绍请求: {}", content);
        String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions";
        
        String systemContent = "你是一个专业的AI技能设计助手。我会给你提供一个完整的skill的内容，请你帮我总结出skill的作用，能够解决的问题，输出一段描述文本";
        SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(), systemContent, content, 0.3, 500, "text");
        String deepseekResponse = "";
        try {
            // 发送HTTP请求到deepseek API
            deepseekResponse = HttpUtil.sendPostRequest(url, skillRequest, deepSeekConfig.getApiKey(), null);
            log.info("Deepseek API响应: {}", deepseekResponse);
            
            // 解析返回结果
            JSONObject responseJson = JSON.parseObject(deepseekResponse);
            List<JSONObject> choices = responseJson.getJSONArray("choices").toJavaList(JSONObject.class);
            
            if (choices != null && !choices.isEmpty()) {
                JSONObject latestChoice = choices.get(0);
                JSONObject message = latestChoice.getJSONObject("message");
                return EscapeCharacterUtils.removeEscapeCharacters( message.getString("content"));//去除转义字符
            }
        } catch (Exception e) {
            log.error("调用Deepseek API失败: {}", e.getMessage(), e);
            throw new BizException("调用Deepseek API失败:"+ e.getMessage()+" Deepseek API响应:"+ deepseekResponse);
        }
        
        return null;
    }
    
    @Override
    public String genIntroduceByDescription(String description) {
        log.info("根据技能描述生成技能介绍请求: {}", description);
        String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions";
        
        String systemContent = "你是一个专业的AI技能设计助手。我会给你提供一个skill的描述，请你基于这个描述，生成一段详细的技能介绍，包括技能的作用、能够解决的问题、使用场景等，输出一段完整的描述文本，请务必严格要找要求输出，绝对不允许输出与要求无关的内容";
        SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(), systemContent, description, 0.3, 500, "text");
        String deepseekResponse = "";
        try {
            // 发送HTTP请求到deepseek API
            deepseekResponse = HttpUtil.sendPostRequest(url, skillRequest, deepSeekConfig.getApiKey(), null);
            log.info("Deepseek API响应: {}", deepseekResponse);
            
            // 解析返回结果
            JSONObject responseJson = JSON.parseObject(deepseekResponse);
            List<JSONObject> choices = responseJson.getJSONArray("choices").toJavaList(JSONObject.class);
            
            if (choices != null && !choices.isEmpty()) {
                JSONObject latestChoice = choices.get(0);
                JSONObject message = latestChoice.getJSONObject("message");
                return EscapeCharacterUtils.removeEscapeCharacters( message.getString("content"));//去除转义字符
            }
        } catch (Exception e) {
            log.error("调用Deepseek API失败: {}", e.getMessage(), e);
            throw new BizException("调用Deepseek API失败:"+ e.getMessage()+" Deepseek API响应:"+ deepseekResponse);
        }
        
        return null;
    }

    @Override
    public CmsContent uploadSkill(String skillUrl) {
        log.info("上传技能压缩包请求: {}", skillUrl);
        String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions";

        // 从数据库中读取cms_tag表的标签信息
        CmsTagDto tagDto = new CmsTagDto();
        tagDto.setDeleteFlag(0);
        tagDto.setStatus(1);
        List<CmsTag> tags = cmsTagService.getList(tagDto);

        // 将标签名称拼接成逗号分隔的字符串
        StringBuilder tagsList = new StringBuilder();
        for (int i = 0; i < tags.size(); i++) {
            CmsTag tag = tags.get(i);
            tagsList.append(tag.getTagId()+"."+tag.getTagName());
            if (i < tags.size() - 1) {
                tagsList.append("，");
            }
        }

        // 构建系统消息内容
        String systemContent = """
                你是一位专业的AI技能包解析助手，需完成以下任务：
                1. 我会提供一个技能包压缩包（格式包含zip/rar）的URL，你需解析该压缩包根目录下的SKILL.md文件; 或者提供一个在线的SKILL.md文件的url；
                2. 基于SKILL.md内容，提炼出：
                  - skill的核心标题（name）；
                  - skill的核心描述（description）；
                  - 详细功能介绍（introduce）；
                  - 从指定标签列表中选取至少3个适配标签（tagList），标签范围：TAG_LIST；
                  - 选择标签的时候只需要输出对应的标签编号
                3. 生成content字段：基于技能包的名称、描述、标签，按照skills目录结构输出完整的技能包YAML内容（包含skills.md本体、scripts目录脚本等），需遵循以下严格规范：
                  - 包含技能包必需的文件和目录；
                  - 多行内容使用「|」字面块表示；
                  - 所有内容从行首开始，无前置空格；
                  - 空目录标注为「children: []」；
                  - 文件内容需具备实际使用价值；
                  - YAML文档需完整，核心概要包含name、version、description、author、created、tags等属性；
                  - 核心节点为structure，用于描述技能包文件目录结构；structure下每个节点需包含基础属性：name、type、path、format、description；content和children为互选属性（type为file时，content字段填写文件内容；type为directory时，children数组填写子目录/文件节点）。
                请将最终结果以JSON格式输出，JSON结构必须包含：name(技能名称),description（技能描述）、introduce（功能介绍）、tagList（标签列表）、content（完整YAML格式技能包内容），无需额外说明，仅输出符合要求的JSON内容。
                """;
        systemContent = systemContent.replace("TAG_LIST", tagsList.toString());
        
        // 构建用户消息内容
        String userContent = skillUrl;
        
        // 创建技能请求
        SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(), systemContent, userContent, 0.5, 8192, "json_object");

        String deepseekResponse = "";
        try {
            // 发送HTTP请求到DeepSeek API
            deepseekResponse = HttpUtil.sendPostRequest(url, skillRequest, deepSeekConfig.getApiKey(), null);
            log.info("Deepseek API响应: {}", deepseekResponse);
            
            // 解析返回结果
            JSONObject responseJson = JSON.parseObject(deepseekResponse);
            List<JSONObject> choices = responseJson.getJSONArray("choices").toJavaList(JSONObject.class);
            
            if (choices != null && !choices.isEmpty()) {
                // 获取最新的choice
                JSONObject latestChoice = choices.get(0);
                JSONObject message = latestChoice.getJSONObject("message");
                String content = message.getString("content");
                
                // 解析content中的JSON
                JSONObject skillJson = JSON.parseObject(content);
                
                // 构建技能生成请求
                SkillGenRequest request = new SkillGenRequest();
                request.setName(skillJson.getString("name"));
                request.setDescription(skillJson.getString("description"));
                request.setIntroduce(skillJson.getString("introduce"));
                request.setTags(skillJson.getJSONArray("tagList").toJavaList(String.class));
                
                // 生成CmsContent对象
                CmsContent cmsContent = getCmsContent(request, skillJson.getString("content"), StpUtil.getLoginIdAsLong(), "");
                List<CmsTag> list = tags.stream().filter(tag -> tag.getTagId() == Long.parseLong(cmsContent.getTags().split(",")[0])).toList();
                if (CollectionUtil.isNotEmpty( list)){
                    cmsContent.setIcon(list.get(0).getIcon());
                }
                // 保存到数据库
                // cmsContentMapper.insert(cmsContent);
                return cmsContent;
            }
        } catch (Exception e) {
            log.error("调用Deepseek API失败: {}", e.getMessage(), e);
            throw new BizException("调用Deepseek API失败:"+ e.getMessage()+" Deepseek API响应:"+ deepseekResponse);
        }
        
        return null;
    }
    
    @Override
    public CmsContent uploadSkillV2(byte[] fileBytes, String fileName) {
        log.info("上传本地技能压缩包请求: {}", fileName);
        
        try {
            // 创建临时文件
            String fileExtension = "";
            if (fileName.contains(".")) {
                int dotIndex = fileName.lastIndexOf(".");
                if (dotIndex != -1) {
                    fileExtension = fileName.substring(dotIndex);
                }
            }
            File tempFile = File.createTempFile("skill", fileExtension);
            try (FileOutputStream fos = new FileOutputStream(tempFile)) {
                fos.write(fileBytes);
            }
            
            // 生成默认参数
            String author = StpUtil.getLoginIdAsString();
            // 从文件名中提取技能名称
            String defaultSkillName = fileName;
            if (fileName.contains(".")) {
                int dotIndex = fileName.lastIndexOf(".");
                if (dotIndex != -1) {
                    defaultSkillName = fileName.substring(0, dotIndex);
                }
            }
            
            // 1. 提取压缩包中的skillMdText
            Map<String, Object> skillInfo = com.kexue.skills.common.util.SkillZipParser.extractSkillMdText(tempFile.getAbsolutePath(), defaultSkillName);
            String skillMdText = (String) skillInfo.get("skillMdText");
            
            // 从数据库中读取cms_tag表的标签信息
            CmsTagDto tagDto = new CmsTagDto();
            tagDto.setDeleteFlag(0);
            tagDto.setStatus(1);
            List<CmsTag> tags = cmsTagService.getList(tagDto);

            // 2. 解析skillMdText获取SkillGenRequest
            SkillGenRequest request = null;
            if (skillMdText != null && !skillMdText.isEmpty()) {
                request = parseSkillMdText(skillMdText, tags);
            } else {
                // 如果没有找到md文件，使用默认值
                request = new SkillGenRequest();
                request.setName(defaultSkillName);
                request.setDescription("未知");
                request.setIntroduce("未知");
                request.setTags(Arrays.asList("1001", "1000"));
            }

            // 3. 使用SkillGenRequest中的信息生成yaml
            String yamlContent = com.kexue.skills.common.util.SkillZipParser.generateYamlFromSkillInfo(
                tempFile.getAbsolutePath(), 
                author, 
                request.getName(), 
                request.getDescription(), 
                request.getTags()
            );
            log.info("解析出skill 压缩包内容：{}", yamlContent);

            // 4. 生成CmsContent对象
            CmsContent cmsContent = getCmsContent(request, yamlContent, StpUtil.getLoginIdAsLong(), "");
            if (Objects.nonNull(cmsContent.getTags())) {
                String s = cmsContent.getTags().split(",")[0];
                long l = 1000;// 默认值
                try {
                    l = Long.parseLong(s);
                } catch (NumberFormatException e) {
                    // 异常是因为大模型返回的tag带中文了，忽略
                }
                long finalL = l;
                List<CmsTag> list = tags.stream().filter(tag -> tag.getTagId() == finalL).toList();
                if (CollectionUtil.isNotEmpty(list)){
                    cmsContent.setIcon(list.get(0).getIcon());
                }
            }
            // 保存到数据库
            // cmsContentMapper.insert(cmsContent);
            // 删除临时文件
            tempFile.delete();
            
            return cmsContent;
        } catch (Exception e) {
            log.error("上传本地技能压缩包失败: {}", e.getMessage(), e);
            throw new BizException("上传本地技能压缩包失败:" + e.getMessage());
        }
    }

    @Override
    public CmsContent uploadSkillV3(String yamlContent) {
        log.info("uploadSkillV3 上传技能压缩包请求: {}", yamlContent);
        try {
            Map<String, Object> yamlMap = YamlToMapUtil.yamlTextToMap(yamlContent);

            Map<String, Object> packageMap = (Map<String, Object>)yamlMap.get("package");
            String skillName = (String) packageMap.get("name");
            String skillDescription = (String) packageMap.get("description");
            List<?> tagList = (List<?>) packageMap.get("tags");
            List<String> tagsStrList = tagList.stream().map(String::valueOf).toList();
            String skillIcon = getDefaultIcon(tagsStrList.get(0));
            SkillGenRequest request = new SkillGenRequest();
            request.setName(skillName);
            request.setDescription(skillDescription);
            request.setTags(tagsStrList);
            request.setIntroduce(genIntroduceByDescription(skillDescription));
            return getCmsContent(request, yamlContent, StpUtil.getLoginIdAsLong(), skillIcon);
        } catch (YAMLException e) {
            throw new BizException("yaml解析失败:"+ e.getMessage());
        }
    }

    private String getDefaultIcon(String tagId){
        CmsTagDto tagDto = new CmsTagDto();
        tagDto.setDeleteFlag(0);
        tagDto.setStatus(1);
        List<CmsTag> tagList = cmsTagService.getList(tagDto);

        String defaultIcon = "";
        for (int i = 0; i < tagList.size(); i++) {
            CmsTag tag = tagList.get(i);
            if (tagId.contains(tag.getTagId()+"")) {
                if (StringUtil.isEmpty(defaultIcon)){
                    defaultIcon = tag.getIcon();
                    break;
                }
            }
        }
        return defaultIcon;
    }

    public SkillGenRequest parseSkillMdText(String skillMdText,List<CmsTag> tags) {
        String url = deepSeekConfig.getBaseUrl() + "/v1/chat/completions";

        // 将标签名称拼接成逗号分隔的字符串
        StringBuilder tagsList = new StringBuilder();
        for (int i = 0; i < tags.size(); i++) {
            CmsTag tag = tags.get(i);
            tagsList.append(tag.getTagId()+"."+tag.getTagName());
            if (i < tags.size() - 1) {
                tagsList.append("，");
            }
        }

        // 构建系统消息内容
        String systemContent = """
                你是一位专业的AI技能包解析助手，需完成以下任务：
                1. 我会提供一个技能包压缩包SKILL.md文件的具体内容；
                2. 基于SKILL.md内容，提炼出：
                  - skill的核心标题（name）；
                  - skill的核心描述（description）；
                  - 详细功能介绍（introduce）；
                  - 从指定标签列表中选取至少3个适配标签（tagList），标签范围：TAG_LIST；
                  - 选择标签的时候只需要输出对应的标签编号，特别注意：只需要标签编号
                请将最终结果以JSON格式输出，JSON结构必须包含：name(技能名称),description（技能描述）、introduce（功能介绍）、tagList（标签列表），无需额外说明，仅输出符合要求的JSON内容。
                """;
        systemContent = systemContent.replace("TAG_LIST", tagsList.toString());

        // 创建技能请求
        SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(), systemContent, skillMdText, 0.5, 8192, "json_object");

        String deepseekResponse = "";
        try {
            // 发送HTTP请求到DeepSeek API
            deepseekResponse = HttpUtil.sendPostRequest(url, skillRequest, deepSeekConfig.getApiKey(), null);
            log.info("Deepseek API响应: {}", deepseekResponse);

            // 解析返回结果
            JSONObject responseJson = JSON.parseObject(deepseekResponse);
            List<JSONObject> choices = responseJson.getJSONArray("choices").toJavaList(JSONObject.class);

            if (choices != null && !choices.isEmpty()) {
                // 获取最新的choice
                JSONObject latestChoice = choices.get(0);
                JSONObject message = latestChoice.getJSONObject("message");
                String content = message.getString("content");

                // 解析content中的JSON
                JSONObject skillJson = JSON.parseObject(content);

                // 构建技能生成请求
                SkillGenRequest request = new SkillGenRequest();
                request.setName(skillJson.getString("name"));
                request.setDescription(skillJson.getString("description"));
                request.setIntroduce(skillJson.getString("introduce"));
                // 处理tagList可能不存在的情况
                if (skillJson.containsKey("tagList")) {
                    request.setTags(skillJson.getJSONArray("tagList").toJavaList(String.class));
                } else {
                    request.setTags(Arrays.asList("1001", "1002"));
                }
                return request;
            }
        } catch (Exception e) {
            log.error("调用Deepseek API失败: {}", e.getMessage(), e);
            throw new BizException("调用Deepseek API失败:"+ e.getMessage()+" Deepseek API响应:"+ deepseekResponse);
        }

        return null;
    }


    @Override
    public CmsContent uploadSkillV4(byte[] fileBytes, String fileName) {
        return null;
    }
}
