package com.cy.guoyan.admin.module.ai.service.chatdocument;

import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cy.guoyan.admin.module.ai.controller.admin.chatdocument.vo.ChatDocumentPageReqVO;
import com.cy.guoyan.admin.module.ai.controller.admin.chatdocument.vo.ChatDocumentSaveReqVO;
import com.cy.guoyan.admin.module.ai.dal.dataobject.chatknowledgedataset.ChatKnowledgeDatasetDO;
import com.cy.guoyan.admin.module.ai.dal.mysql.chatknowledgedataset.ChatKnowledgeDatasetMapper;
import com.cy.guoyan.admin.module.ai.util.DifyClient;
import com.cy.guoyan.admin.module.infra.api.file.FileApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.io.File;
import java.io.IOException;
import java.util.*;
import com.cy.guoyan.admin.module.ai.dal.dataobject.chatdocument.ChatDocumentDO;
import com.cy.guoyan.admin.framework.common.pojo.PageResult;
import com.cy.guoyan.admin.framework.common.util.object.BeanUtils;
import com.cy.guoyan.admin.module.ai.dal.mysql.chatdocument.ChatDocumentMapper;
import org.springframework.web.multipart.MultipartFile;
import static com.cy.guoyan.admin.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cy.guoyan.admin.module.system.enums.ErrorCodeConstants.*;

/**
 * 知识库文档 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@Slf4j
public class ChatDocumentServiceImpl implements ChatDocumentService {

    @Resource
    private ChatDocumentMapper chatDocumentMapper;

    @Resource
    private ChatKnowledgeDatasetMapper chatKnowledgeDatasetMapper;

    @Resource
    private FileApi fileApi;

    private final DifyClient difyClient;

    public ChatDocumentServiceImpl(DifyClient difyClient) {
        this.difyClient = difyClient;
    }
//    private static final String FILE_STORAGE_PATH = "/Users/shun/Desktop/tsinghua/files/";


    /**
     * 创建知识库文档：先存库，再调用 Dify 接口上传文件，如果上传成功则更新记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JSONObject createChatDocument(ChatDocumentSaveReqVO vo, MultipartFile file) throws IOException {

        ChatKnowledgeDatasetDO dataset = chatKnowledgeDatasetMapper.selectById(vo.getId());
        if (dataset == null) {
            throw exception(CHAT_KNOWLEDGE_DATASET_NOT_EXISTS);
        }

        vo.setId(null);
        // 1. 插入 DB
        ChatDocumentDO doc = BeanUtils.toBean(vo, ChatDocumentDO.class);
        doc.setDataSourceType("file_upload");
        doc.setDatasetId(vo.getDatasetId());
        doc.setProcessRuleMode(vo.getProcessRuleMode());

        // 2. 如果带了文件，就调用 Dify 上传
        JSONObject difyResp = null;
        if (file != null && !file.isEmpty()) {
            String originalFilename = file.getOriginalFilename();

            Map<String, Object> apiFile = fileApi.getFile(originalFilename,IoUtil.readBytes(file.getInputStream()),"restricted");
            log.info("DEBUG - File Upload Response: {}", apiFile);
            String fileUrl = apiFile.get("path").toString();
//            Long fileConfId = Long.valueOf(apiFile.get("configId").toString());
            doc.setFilePath(fileUrl);
//            doc.setFileConfId(fileConfId);

            // 准备临时文件
            File tmp = File.createTempFile("dify_", "_" + file.getOriginalFilename());
            file.transferTo(tmp);
            tmp.deleteOnExit();
            doc.setName(originalFilename);
            chatDocumentMapper.insert(doc);

            // 构建请求 metadata
            Map<String, Object> data = new HashMap<>();
            data.put("datasetId", dataset.getDifyDatasetId());
            data.put("name", originalFilename);
            data.put("indexing_technique", "high_quality");
            data.put("doc_form", "text_model");
            Map<String, Object> processRule = new HashMap<>();
            if (Objects.equals("custom",vo.getProcessRuleMode())) {
                processRule.put("mode", "custom");
                // 预处理规则
                Map<String, Object> rules = new HashMap<>();
                List<Map<String, Object>> preProcessingRules = new ArrayList<>();
                Map<String, Object> rule1 = new HashMap<>();
                rule1.put("id", "remove_extra_spaces");
                rule1.put("enabled", true);
                preProcessingRules.add(rule1);
                Map<String, Object> rule2 = new HashMap<>();
                rule2.put("id", "remove_urls_emails");
                rule2.put("enabled", true);
                preProcessingRules.add(rule2);
                rules.put("pre_processing_rules", preProcessingRules);

                // 分段规则
                Map<String, Object> segmentation = new HashMap<>();
                segmentation.put("separator", "\n\n");
                segmentation.put("max_tokens", 500);
                rules.put("segmentation", segmentation);
                processRule.put("rules", rules);
            }else {
                processRule.put("mode", "automatic");
            }
            data.put("process_rule", processRule);

            difyResp = difyClient.createDocumentByFile(tmp, originalFilename, data);

            // 3. 更新本地记录
            JSONObject docJson = difyResp.getJSONObject("document");
            doc.setDifyDocumentId(docJson.getString("id"));
            doc.setWordCount(docJson.getIntValue("word_count"));
            doc.setIndexingStatus(docJson.getString("indexing_status"));
            doc.setBatch(difyResp.getString("batch"));
            doc.setFileSize(apiFile.get("size").toString());
            chatDocumentMapper.updateById(doc);

            // 启动异步轮询线程
            new Thread(() -> {
                try {
                    pollStatusUntilComplete(doc);
                } catch (Exception e) {
                    log.error("异步轮询 Dify 状态失败", e);
                }
            }).start();


        }

        // 4. 返回 DB 主键 & Dify 响应
        JSONObject result = new JSONObject();
        result.put("id", doc.getId());
        result.put("dify", difyResp);
        return result;
    }


    @Override
    public void updateChatDocument(ChatDocumentSaveReqVO updateReqVO) {
        // 校验存在
        validateChatDocumentExists(updateReqVO.getId());
        // 更新
        ChatDocumentDO updateObj = BeanUtils.toBean(updateReqVO, ChatDocumentDO.class);
        chatDocumentMapper.updateById(updateObj);
    }

    @Override
    @Transactional
    public void deleteChatDocument(Long id) throws IOException {
        ChatDocumentDO documentDO = chatDocumentMapper.selectById(id);
        if (documentDO == null) {
            throw exception(CHAT_DOCUMENT_NOT_EXISTS);
        }
        ChatKnowledgeDatasetDO aDo = chatKnowledgeDatasetMapper.selectById(documentDO.getDatasetId());
        difyClient.deleteDocument(aDo.getDifyDatasetId(), documentDO.getDifyDocumentId());
        chatDocumentMapper.deleteById(id);
    }

    private void validateChatDocumentExists(Long id) {
        if (chatDocumentMapper.selectById(id) == null) {
            throw exception(CHAT_DOCUMENT_NOT_EXISTS);
        }
    }

    @Override
    public ChatDocumentDO getChatDocument(Long id) {
        return chatDocumentMapper.selectById(id);
    }

    @Override
    public PageResult<ChatDocumentDO> getChatDocumentPage(ChatDocumentPageReqVO pageReqVO) {
        return chatDocumentMapper.selectPage(pageReqVO);
    }



    @Override
    public JSONObject getDocumentIndexingStatus(String datasetId, String batch) throws IOException {
        new Thread(() -> {
            try {
                pollStatusUntilComplete(new ChatDocumentDO().setDatasetId(datasetId).setBatch(batch));
            } catch (Exception e) {
                log.error("异步轮询 Dify 状态失败", e);
            }
        }).start();


        return difyClient.getDocumentIndexingStatus(datasetId, batch);

    }

    public void pollStatusUntilComplete(ChatDocumentDO doc) throws Exception {
        int waited = 0;
        while (waited < 60*60*24) { // 最多等1天
            JSONObject status = difyClient.getDocumentIndexingStatus(doc.getDatasetId(), doc.getBatch());
            JSONArray array = status.getJSONArray("data");
            if (array == null || array.isEmpty()) {
                log.warn("文档处理状态为空 name={} 状态：{}", doc.getName(), status);
                return;
            }
            JSONObject item = array.getJSONObject(0);
            String state = item.getString("indexing_status");
            Integer completedSegments = item.getInteger("completed_segments");
            log.info("文档处理状态 name={} 状态：{},分段：{}", doc.getName(), state,  completedSegments);
            if ("completed".equals(state)) {
                if (doc.getId() == null) {
                    ChatDocumentDO aDo = chatDocumentMapper.selectOne("dataset_id", doc.getDatasetId(), "batch", doc.getBatch());
                    doc.setId(aDo.getId());
                    doc.setCreator(aDo.getCreator());
                    doc.setUpdater(aDo.getUpdater());
                    doc.setName(aDo.getName());
                }
                log.info("文档处理完成 name={} ✅",  doc.getName());
//                doc.setHitCount(completedSegments);
                doc.setIndexingStatus("completed");
                doc.setCompletedSegments(completedSegments);
                try {
                    JSONObject jsonObject = difyClient.listDocuments(doc.getDatasetId(), doc.getName(), null, null);
                    JSONArray dataArray = jsonObject.getJSONArray("data");
                    if (!dataArray.isEmpty()) {
                        JSONObject firstDocument = dataArray.getJSONObject(0);
                        // 提取 "word_count" 字段
                        int wordCount = firstDocument.getIntValue("word_count");
                        doc.setWordCount(wordCount);
                    }
                } catch (Exception e) {
                    log.error("获取文档信息失败", e);
                }
                chatDocumentMapper.updateById(doc);
                return;
            } else if ("failed".equals(state)) {
                log.warn("文档处理失败 name={} ❌ 错误：{}", doc.getName(), status.getString("error"));
                // 可更新失败状态
                return;
            }
            Thread.sleep(3000);
            waited += 3;
        }
        log.warn("轮询超时 name={} ⏰", doc.getName());
    }



    @Override
    public void deleteDocument(String datasetId, String documentId) throws IOException {

        difyClient.deleteDocument(datasetId, documentId);
    }

    @Override
    public JSONObject addDocumentSegments(String datasetId, String documentId, List<Map<String, Object>> segments1) throws IOException {

        List<Map<String, Object>> segments = new ArrayList<>();
        Map<String, Object> segment = new HashMap<>();
        segment.put("content", "上海");
        segment.put("answer", "20万"); // 可选
        segment.put("keywords", Arrays.asList("烟", "双喜")); // 可选
        segments.add(segment);

        return difyClient.addDocumentSegments(datasetId, documentId, segments);

    }

    @Override
    public JSONObject listDocuments(String datasetId, String keyword, Integer page, Integer limit) throws IOException {

        return difyClient.listDocuments(datasetId, keyword, page, limit);

    }

    @Override
    public JSONObject listDocumentSegments(String datasetId, String documentId, String keyword, String status) throws IOException {

        return difyClient.listDocumentSegments(datasetId, documentId, keyword, status);

    }

    @Override
    public void deleteDocumentSegment(String datasetId, String documentId, String segmentId) throws IOException {

        difyClient.deleteDocumentSegment(datasetId, documentId, segmentId);

    }

    @Override
    public JSONObject getUploadedFileInfo(String datasetId, String documentId) throws IOException {

        return difyClient.getUploadedFileInfo(datasetId, documentId);


    }

//    @Override
//    public JSONObject updateDocumentSegment(
//            String datasetId,
//            String documentId,
//            String segmentId,
//            String content,
//            String answer,
//            List<String> keywords,
//            Boolean enabled
//    ) throws IOException {
//
//        String url = difyBaseUrl + "/v1/datasets/" + datasetId + "/documents/" + documentId + "/segments/" + segmentId;
//
//        CloseableHttpClient httpClient = HttpClients.createDefault();
//        try {
//            HttpPost httpPost = new HttpPost(url);
//            httpPost.setHeader("Authorization", "Bearer " + difyApiKey);
//            httpPost.setHeader("Content-Type", "application/json");
//
//            // 构建 JSON 请求体
//            JSONObject segment = new JSONObject();
//            segment.put("content", content);
//            if (answer != null) {
//                segment.put("answer", answer);
//            }
//            if (keywords != null) {
//                segment.put("keywords", keywords);
//            }
//            if (enabled != null) {
//                segment.put("enabled", enabled);
//            }
//
//            JSONObject requestBody = new JSONObject();
//            requestBody.put("segment", segment);
//
//            httpPost.setEntity(new StringEntity(requestBody.toJSONString(), StandardCharsets.UTF_8));
//
//            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
//                int statusCode = response.getStatusLine().getStatusCode();
//                String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
//
//                if (statusCode != 200) {
//                    throw new IOException("更新分段失败，状态码：" + statusCode + "，响应内容：" + responseBody);
//                }
//
//                return JSONObject.parseObject(responseBody);
//            }
//        } finally {
//            httpClient.close();
//        }
//    }




}