package org.jk.rag.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jk.common.core.domain.R;
import org.jk.common.core.utils.StringUtils;
import org.jk.common.excel.utils.ExcelUtil;
import org.jk.common.idempotent.annotation.RepeatSubmit;
import org.jk.common.log.annotation.Log;
import org.jk.common.log.enums.BusinessType;
import org.jk.common.mybatis.core.page.PageQuery;
import org.jk.common.mybatis.core.page.TableDataInfo;
import org.jk.common.satoken.utils.LoginHelper;
import org.jk.common.web.core.BaseController;
import org.jk.rag.domain.dto.DocumentFileDTO;
import org.jk.rag.domain.entity.*;
import org.jk.rag.domain.vo.KnowledgeSliceVo;
import org.jk.rag.mapper.JkDocumentMapper;
import org.jk.rag.service.IJkRagService;
import org.jk.rag.utils.SnowflakeDigitGenerator;
import org.jk.system.domain.vo.SysOssVo;
import org.jk.system.service.ISysOssService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/deepseek/api")
public class JkRagDocumentController extends BaseController {


    private final IJkRagService iJkRagService;

    private final JkDocumentMapper jkDocumentMapper;

    private final ISysOssService sysOssService;

    /**
     * 知识列表
     *
     * @param params
     * @return
     */
    @PostMapping("/documentList")
    public TableDataInfo documentList(@RequestBody JkDocumentParams params,@RequestBody PageQuery pageQuery) {
        IPage<JkDocument> list = iJkRagService.documentPageList(params,pageQuery);
        return TableDataInfo.build(list);
    }



    /**
     * 知识详情
     *
     * @param documentId
     * @return
     */
    @GetMapping("/documentDetail/{documentId}")
    public R<JkDocument> documentDetail(@PathVariable String documentId) {
        return R.ok(iJkRagService.documentDetail(documentId));
    }

    /**
     * 更新知识
     *
     * @param params
     * @param documentId
     * @return
     */
    @PutMapping("/updateDocument/{documentId}")
    @RepeatSubmit
    public R<Integer> updateDocument(@RequestBody JkDocumentParams params, @PathVariable String documentId) {
        int i = iJkRagService.updateDocument(params, documentId);
        return R.ok(i);
    }

    /**
     * 删除知识
     *
     * @param documentId
     * @return
     */
    //@SaCheckPermission("knowledgeLib:detail:del")
    @DeleteMapping("/delDocument/{documentId}")
    public R<Integer> delDocument(@PathVariable String documentId) {
        int i = iJkRagService.delDocument(documentId);
        return R.ok(i);
    }

    /**
     * 删除知识
     *
     * @param documentId
     * @return
     */
    //@SaCheckPermission("knowledgeLib:detail:del")
    @DeleteMapping("/delUnfinishedDocument/{documentId}")
    public R<Integer> delUnfinishedDocument(@PathVariable String documentId) {
        int i = iJkRagService.delUnfinishedDocument(documentId);
        return R.ok(i);
    }

    /**
     * 上传知识文件
     *
     * @param params
     * @param knowledgeId
     * @return
     * @throws Exception
     */
    //@SaCheckPermission("knowledgeLib:detail:update")
    @PostMapping("/uploadDocument/{knowledgeId}") //@RequestPart DocumentParams documentParams,
    @RepeatSubmit
    public R<Void> uploadDocument(@RequestBody JkDocumentParams params,
                                     @PathVariable String knowledgeId) throws Exception {
        for (OssParms ossParms : params.getFileList()) {
            if(null == ossParms.getOssId()) {
                throw new RuntimeException("请文件上传完成后再进行提交！");
            }
        }
        params.setUserId(String.valueOf(LoginHelper.getUserId()));
        params.setTenantId(LoginHelper.getTenantId());
        params.setKnowledge_id(knowledgeId);
        List<JkDocument> documentList = new ArrayList<>();
        for (OssParms ossParms : params.getFileList()) {
            // 1. 生成文档ID
            SnowflakeDigitGenerator documentIdGenerator = new SnowflakeDigitGenerator(1, 1);

            JkSliceDocument oldDocument = jkDocumentMapper.selectDocumentByOssId(ossParms.getOssId(),params.getCustomSeparator(),params.getSliceValue(),params.getParsingType(),params.getStandardClassification());
            long documentId = documentIdGenerator.nextId();
            String fullDocumentId = "a" + documentId;
            params.setDocumentId(fullDocumentId);
            SysOssVo sysOssVo = sysOssService.getById(Long.valueOf(ossParms.getOssId()));
            JkDocument document = JkDocument.builder()
                .documentId(fullDocumentId)
                .knowledgeId(params.getKnowledge_id())
                .customSeparator(oldDocument != null ? oldDocument.getCustomSeparator(): params.getCustomSeparator())
                .name(params.getStandardClassification().equals("3")?params.getName():ossParms.getName())
                .suffix(ossParms.getSuffix())
                .url(ossParms.getUrl())
                .ossId(ossParms.getOssId())
                .remark(params.getRemark())
                .length(sysOssVo!= null ? sysOssVo.getSize() :null)
                .parsingType(oldDocument != null ? oldDocument.getParsingType(): params.getParsingType())
                .status("3")
                .standardClassification(oldDocument != null ? oldDocument.getStandardClassification(): params.getStandardClassification())
                .createBy(LoginHelper.getUserId())
                .createTime(new Date())
                .sliceValue(params.getSliceValue())
                .build();
            jkDocumentMapper.insertDocument(document);
            documentList.add(document);
        }
        try {
            // 异步执行处理任务
            CompletableFuture.runAsync(() -> {
                try {
                    iJkRagService.uploadDocument(params,documentList,true);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            return R.ok();
        } catch (Exception e) {
            return R.fail();
        }
    }

    /**
     * python文档解析回调接口
     *
     * @param params
     * @return
     * @throws Exception
     */
    @PostMapping("/updateDocumentByPython") //@RequestPart DocumentParams documentParams,
    @RepeatSubmit
    public R<Void> updateDocumentByPython(@RequestBody JkDocumentPythonParams params) throws Exception {
        iJkRagService.updateDocumentByPython(params);
        return R.ok();
    }


    /**
     * 获取知识配置信息
     *
     * @param documentId
     * @return
     */
    @GetMapping("/documentSetting/{documentId}")
    public R<JkDocumentSettings> documentSetting(@PathVariable String documentId) {
        JkDocumentSettings json = iJkRagService.documentSetting(documentId);
        return R.ok(json);
    }

    /**
     * 更新知识配置详情
     *
     * @param params
     * @param documentId
     * @return
     */
    @PutMapping("/updateDocumentSetting/{documentId}")
    @RepeatSubmit
    public R<Integer> updateDocumentSetting(@RequestBody JkDocumentParams params, @PathVariable String documentId) {
        params.setUserId(String.valueOf(LoginHelper.getUserId()));
        params.setTenantId(LoginHelper.getTenantId());
        params.setDocumentId(documentId);
        JkDocument document = jkDocumentMapper.selectTargetDocument(JkDocument.builder().documentId(documentId).build());
        List<JkDocument> documentList = new ArrayList<>();
        if (document != null) {
            if((null != document.getParsingType()&& null != params.getParsingType()  && document.getParsingType().equals(params.getParsingType()))
                && (null != document.getCustomSeparator() && null != params.getCustomSeparator() && document.getCustomSeparator().equals(params.getCustomSeparator())))
            {
                     if(params.getCustomSeparator().equals("0")) {
                         if(params.getSliceValue().equals(document.getSliceValue())  ) {
                             return R.ok(1);
                         }
                     }
                return R.ok(1);
            }
        }
        if(params.getStandardClassification().equals(document.getStandardClassification())) {
            if(params.getStandardClassification().equals("3") ){
                if(params.getName().equals(document.getName())&& params.getRemark().equals(document.getRemark())) {
                    return R.ok(1);
                }
            }
        }

        JkDocumentSettings settings = new JkDocumentSettings();
        settings.setKnowledgeId(params.getKnowledge_id());
        document.setParsingType(params.getParsingType());
        document.setStandardClassification(params.getStandardClassification());
        document.setCustomSeparator(params.getCustomSeparator());
        document.setUpdateBy(LoginHelper.getUserId());
        document.setStatus("3");
        document.setCustomSeparator(params.getCustomSeparator());
        document.setSliceValue(params.getSliceValue());
        jkDocumentMapper.updateDocument(document);
        documentList.add(document);
        int i = iJkRagService.updateDocumentSetting(params, documentId);
        if( i == 1 ) {
            // 异步执行处理任务
            CompletableFuture.runAsync(() -> {
                try {
                    iJkRagService.uploadDocument(params,documentList,false);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }
        return R.ok(1);
    }

    /**
     * 审核
     * @param params
     * @param appId
     * @return
     */
    @PutMapping("/updateDocumentAudit/{appId}")
    public R<Integer> updateAuditApplication(@RequestBody JkApplicationParams params, @PathVariable String appId) {
        int i = iJkRagService.updateAuditApplication(params, appId);
        return R.ok(i);
    }

    //@SaCheckPermission("knowledgeLib:detail:exportSlice")
    @Log(title = "下载文档切片", businessType = BusinessType.EXPORT)
    @PostMapping("/documentSliceExport")
    public void documentSliceExport(HttpServletResponse response, @RequestBody JkDocumentExportParams parms)
    {
        List<KnowledgeSliceVo> list = iJkRagService.selectExportDocumentSlice(parms.getDocumentIds());
        ExcelUtil.exportExcel(list, "文档切片数据", KnowledgeSliceVo.class,response);
    }

    //@SaCheckPermission("knowledgeLib:detail:exportMd")
    @Log(title = "下载文档", businessType = BusinessType.EXPORT)
    @PostMapping("/documentExport")
    public void  documentExport(HttpServletResponse response, @RequestBody JkDocumentExportParams parms) throws IOException {

        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=\"documents.zip\"");

        // 使用 StreamingResponseBody 来实现流式响应
        iJkRagService.downloadDocument(parms.getDocumentIds() ,response.getOutputStream());

    }

    //@SaCheckPermission("knowledgeLib:detail:exportOr")
    @Log(title = "下载文档", businessType = BusinessType.EXPORT)
    @PostMapping("/documentFileExport")
    public void  documentFileExport(HttpServletResponse response, @RequestBody JkDocumentExportParams parms) throws IOException {

        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=\"documents.zip\"");

        // 使用 StreamingResponseBody 来实现流式响应
        iJkRagService.downloadFileDocument(parms.getDocumentIds() ,response.getOutputStream());

    }

    /**
     * 引用文件列表
     *
     * @param params
     * @return
     */
    @PostMapping("/quoteDocumentList")
    public TableDataInfo quoteDocumentList(@RequestBody JkDocumentParams params, @RequestBody PageQuery pageQuery) {
        IPage<JkQuoteDocument> list = iJkRagService.quoteDocumentPageList(params,pageQuery);
        return TableDataInfo.build(list);
    }

    /**
     * 引用知识文件
     *
     * @param params
     * @return
     */
    @SaCheckPermission("knowledgeLib:detail:quote")
    @PostMapping("/importDocumentList")
    public R<Void> importDocumentList(@RequestBody JkDocumentExportParams params) {
        iJkRagService.importDocumentList(params);
        return R.ok();
    }

    /**
     * 检查同知识库是否有相同文件
     *
     * @param params
     * @return
     */
    @PostMapping("/document/checkFile")
    public R<List<Map<String,String>>> documentSetting(@RequestBody DocumentFileDTO params) {
        List<Map<String,String>> result = new ArrayList<>();
        for(OssParms ossParms :params.getOssParms()) {
            Map<String,String> re = new HashMap<>();
            String oldName = iJkRagService.checkDocumentFile(params,ossParms);
            if(StringUtils.isNotBlank(oldName)) {
                re.put("oldName",oldName);
                re.put("newName",ossParms.getName());
                re.put("ossId",ossParms.getOssId());
                result.add(re);
            }
        }
        return R.ok(result);
    }

    /**
     * 检查同知识库是否有相同文件
     *
     * @param params
     * @return
     */
    @PostMapping("/document/checkQuoteFile")
    public R<List<Map<String,String>>> checkQuoteFile(@RequestBody JkDocumentExportParams params) {
        List<Map<String,String>> result = new ArrayList<>();
        for(String documentId :params.getDocumentIds()) {
            Map<String,String> re = new HashMap<>();
            BmDocument bmDocument = jkDocumentMapper.selectById(documentId);
            String oldName = iJkRagService.selQouteDocumentFile(bmDocument,params.getKnowledgeId());
            if(StringUtils.isNotBlank(oldName)) {
                re.put("oldName",oldName);
                re.put("newName",bmDocument.getName());
                re.put("documentId",documentId);
                result.add(re);
            }
        }
        return R.ok(result);
    }


}
