package org.xyzh.ai.controller;

import com.alibaba.fastjson2.JSONObject;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.xyzh.api.ai.service.DifyProxyService;
import org.xyzh.api.ai.service.KnowledgeService;
import org.xyzh.api.ai.dto.TbKnowledge;
import org.xyzh.api.ai.dto.TbKnowledgeFile;
import org.xyzh.api.ai.vo.KnowledgeFileVO;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.utils.validation.ValidationResult;
import org.xyzh.common.utils.validation.ValidationUtils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 * @description 知识库控制器
 * @filename KnowledgeController.java
 * @author yslg
 * @copyright xyzh
 * @since 2025-12-17
 */
@RestController
@Validated
@RequestMapping("/ai/knowledge")
public class KnowledgeController {
    private static final Logger logger = LoggerFactory.getLogger(KnowledgeController.class);

    @Autowired
    private KnowledgeService knowledgeService;

    @Autowired
    private DifyProxyService difyProxyService;

    // ====================== 知识库管理 ======================

    /**
     * @description    创建知识库基础信息，包含dify知识库各种参数的配置
     * @param    knowledge
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:create')")
    @PostMapping
    public ResultDomain<TbKnowledge> createKnowledge(@RequestBody TbKnowledge knowledge) {
        ValidationResult result = ValidationUtils.validate(knowledge, Arrays.asList(
            ValidationUtils.requiredString("title", "知识库标题", 1, 50),
            ValidationUtils.inSet("difyIndexingTechnique", "Dify索引方式（high_quality/economy）" , true, new HashSet<>(Arrays.asList("high_quality", "economy"))),
            ValidationUtils.inSet("category", "所属分类  workcase 内部知识库、外部知识库", true, new HashSet<>(Arrays.asList("default", "内部知识库", "外部知识库")))
        ));
        if(!result.isValid()){
            return ResultDomain.failure(result.getAllErrors());
        }
        logger.info("创建知识库: title={}", knowledge.getTitle());
        return knowledgeService.createKnowledge(knowledge);
    }

    /**
     * @description    更新知识库，包含dify知识库各种参数的配置
     * @param    knowledge
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:update')")
    @PutMapping
    public ResultDomain<TbKnowledge> updateKnowledge(@RequestBody @Valid TbKnowledge knowledge) {
        ValidationResult result = ValidationUtils.validate(knowledge, Arrays.asList(
            ValidationUtils.requiredString("title", "知识库标题", 1, 50),
            ValidationUtils.inSet("difyIndexingTechnique", "Dify索引方式（high_quality/economy）" , true, new HashSet<>(Arrays.asList("high_quality", "economy"))),
            ValidationUtils.inSet("category", "所属分类  workcase 内部知识库、外部知识库", true, new HashSet<>(Arrays.asList("default", "内部知识库", "外部知识库")))

        ));
        if(!result.isValid()){
            return ResultDomain.failure(result.getAllErrors());
        }
        logger.info("更新知识库: knowledgeId={}", knowledge.getKnowledgeId());
        return knowledgeService.updateKnowledge(knowledge);
    }

    /**
     * @description    删除知识库，同时删除dify知识库
     * @param    knowledgeId
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:delete')")
    @DeleteMapping("/{knowledgeId}")
    public ResultDomain<Boolean> deleteKnowledge(@PathVariable("knowledgeId") @NotBlank String knowledgeId) {
        logger.info("删除知识库: knowledgeId={}", knowledgeId);
        return knowledgeService.deleteKnowledge(knowledgeId);
    }

    /**
     * @description    获取知识库详情，包含dify知识库各种参数的配置
     * @param    knowledgeId
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:view')")
    @GetMapping("/{knowledgeId}")
    public ResultDomain<TbKnowledge> getKnowledge(@PathVariable("knowledgeId") @NotBlank String knowledgeId) {
        logger.info("获取知识库: knowledgeId={}", knowledgeId);
        return knowledgeService.getKnowledgeById(knowledgeId);
    }

    /**
     * @description    查询知识库列表
     * @param    filter
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:view')")
    @PostMapping("/list")
    public ResultDomain<TbKnowledge> listKnowledges(@RequestBody(required = false) TbKnowledge filter) {
        logger.info("查询知识库列表");
        return knowledgeService.listKnowledges(filter);
    }

    /**
     * @description    分页查询知识库
     * @param    pageRequest
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:view')")
    @PostMapping("/page")
    public ResultDomain<TbKnowledge> pageKnowledges(@RequestBody @Valid PageRequest<TbKnowledge> pageRequest) {
        logger.info("分页查询知识库");
        return knowledgeService.pageKnowledges(pageRequest.getFilter(), pageRequest.getPageParam());
    }

    /**
     * @description    获取知识库统计信息
     * @param    knowledgeId
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:view')")
    @GetMapping("/{knowledgeId}/stats")
    public ResultDomain<TbKnowledge> getKnowledgeStats(@PathVariable("knowledgeId") @NotBlank String knowledgeId) {
        logger.info("获取知识库统计: knowledgeId={}", knowledgeId);
        return knowledgeService.getKnowledgeStats(knowledgeId);
    }

    // ====================== 文件管理 ======================

    /**
     * @description    获取知识库文档列表（含文件详细信息）
     * @param    pageRequest 分页请求
     * @author    yslg
     * @since 2025-12-20
     */
    @PreAuthorize("hasAuthority('ai:knowledge:file:view')")
    @PostMapping("/{knowledgeId}/documents")
    public ResultDomain<KnowledgeFileVO> getDocumentList(@RequestBody PageRequest<TbKnowledgeFile> pageRequest) {
        logger.info("获取文档列表: knowledgeId={}", pageRequest.getFilter().getKnowledgeId());
        return knowledgeService.getDocumentList(pageRequest);
    }

    /**
     * @description    上传文件到知识库（同步到Dify）
     * @param    file 上传文件
     * @param    knowledgeId 知识库id
     * @param    indexingTechnique 索引方式
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:file:upload')")
    @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResultDomain<TbKnowledgeFile> uploadToKnowledge(
            @RequestParam("file") @NotNull MultipartFile file,
            @RequestParam("knowledgeId") @NotBlank String knowledgeId,
            @RequestParam(value = "indexingTechnique", required = false) String indexingTechnique) {
        logger.info("上传知识库文件: knowledgeId={}, fileName={}", knowledgeId, file.getOriginalFilename());
        return knowledgeService.uploadKnowledgeFile(knowledgeId, file, indexingTechnique);
    }

    /**
     * @description    批量上传文件到知识库
     * @param    files 文件数组
     * @param    knowledgeId 知识库id
     * @param    indexingTechnique 索引方式
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:file:upload')")
    @PostMapping(value = "/file/batch-upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResultDomain<TbKnowledgeFile> batchUploadToKnowledge(
            @RequestParam("files") @NotEmpty List<MultipartFile> files,
            @RequestParam("knowledgeId") @NotBlank String knowledgeId,
            @RequestParam(value = "indexingTechnique", required = false) String indexingTechnique) {
        logger.info("批量上传知识库文件: knowledgeId={}, fileCount={}", knowledgeId, files.size());
        return knowledgeService.batchUploadKnowledgeFile(knowledgeId, files, indexingTechnique);
    }

    /**
     * 上传新文件来更新知识库文件，注意fileRootId一致，生成新id
     * @param    file 上传文件
     * @param    knowledgeId 知识库id
     * @param    fileRootId 文件Rootid，多version下一致
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:file:update')")
    @PutMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResultDomain<TbKnowledgeFile> updateFile(
            @RequestParam("file") @NotNull MultipartFile file,
            @RequestParam("knowledgeId") @NotBlank String knowledgeId,
            @RequestParam("fileRootId") @NotBlank String fileRootId) {
        logger.info("更新知识库文件: knowledgeId={}, fileName={}", knowledgeId, file.getOriginalFilename());
        return knowledgeService.updateKnowledgeFileVersion(knowledgeId, file, fileRootId);
    }

    /**
     * 删除知识库文件（同时删除Dify文档），所有filtRootId的文件一起软删除
     * @param    fileId 文件id
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:file:delete')")
    @DeleteMapping("/file/{fileRootId}")
    public ResultDomain<Boolean> deleteFile(@PathVariable("fileRootId") @NotBlank String fileRootId) {
        logger.info("删除知识库文件: fileId={}", fileRootId);
        return knowledgeService.deleteKnowledgeFileById(fileRootId);
    }

    /**
     * 获取文件历史版本，获取fileRootId下所有version
     * @param    fileRootId 文件根ID
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:knowledge:file:view')")
    @GetMapping("/file/{fileRootId}/history")
    public ResultDomain<KnowledgeFileVO> getFileHistory(@PathVariable("fileRootId") @NotBlank String fileRootId) {
        logger.info("获取文件历史: fileRootId={}", fileRootId);
        return knowledgeService.getKnowledgeFileHistory(fileRootId);
    }

    // ====================== 文档分段管理 ======================

    /**
     * @description    获取文档分段列表
     * @param    datasetId Dify数据集ID
     * @param    documentId Dify文档ID
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:dify:segment:view')")
    @GetMapping("/datasets/{datasetId}/documents/{documentId}/segments")
    public ResultDomain<JSONObject> getDocumentSegments(
            @PathVariable("datasetId") @NotBlank String datasetId,
            @PathVariable("documentId") @NotBlank String documentId) {
        logger.info("获取文档分段: datasetId={}, documentId={}", datasetId, documentId);
        return difyProxyService.getDocumentSegments(datasetId, documentId);
    }

    /**
     * @description    创建文档分段
     * @param    datasetId Dify数据集ID
     * @param    documentId Dify文档ID
     * @param    requestBody 分段内容
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:dify:segment:create')")
    @PostMapping("/datasets/{datasetId}/documents/{documentId}/segments")
    public ResultDomain<String> createSegment(
            @PathVariable("datasetId") @NotBlank String datasetId,
            @PathVariable("documentId") @NotBlank String documentId,
            @RequestBody Map<String, Object> requestBody) {
        logger.info("创建文档分段: datasetId={}, documentId={}", datasetId, documentId);
        return difyProxyService.createSegment(datasetId, documentId, requestBody);
    }

    /**
     * @description    更新文档分段
     * @param    datasetId Dify数据集ID
     * @param    documentId Dify文档ID
     * @param    segmentId Dify分段ID
     * @param    requestBody 分段内容
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:dify:segment:update')")
    @PatchMapping("/datasets/{datasetId}/documents/{documentId}/segments/{segmentId}")
    public ResultDomain<String> updateSegment(
            @PathVariable("datasetId") @NotBlank String datasetId,
            @PathVariable("documentId") @NotBlank String documentId,
            @PathVariable("segmentId") @NotBlank String segmentId,
            @RequestBody Map<String, Object> requestBody) {
        logger.info("更新文档分段: datasetId={}, documentId={}, segmentId={}", datasetId, documentId, segmentId);
        return difyProxyService.updateSegment(datasetId, documentId, segmentId, requestBody);
    }

    /**
     * @description    删除文档分段
     * @param    datasetId Dify数据集ID
     * @param    documentId Dify文档ID
     * @param    segmentId Dify分段ID
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:dify:segment:delete')")
    @DeleteMapping("/datasets/{datasetId}/documents/{documentId}/segments/{segmentId}")
    public ResultDomain<String> deleteSegment(
            @PathVariable("datasetId") @NotBlank String datasetId,
            @PathVariable("documentId") @NotBlank String documentId,
            @PathVariable("segmentId") @NotBlank String segmentId) {
        logger.info("删除文档分段: datasetId={}, documentId={}, segmentId={}", datasetId, documentId, segmentId);
        return difyProxyService.deleteSegment(datasetId, documentId, segmentId);
    }

    // ====================== 文档状态管理 ======================

    /**
     * @description    更新文档状态（启用/禁用/归档）
     * @param    datasetId Dify数据集ID
     * @param    action 操作类型: enable/disable/archive/un_archive
     * @param    requestBody 请求体
     * @author    yslg
     * @since 2025-12-18
     */
    @PreAuthorize("hasAuthority('ai:dify:document:status')")
    @PatchMapping("/datasets/{datasetId}/documents/{action}/status")
    public ResultDomain<String> updateDocumentStatus(
            @PathVariable("datasetId") @NotBlank String datasetId,
            @PathVariable("action") @NotBlank String action,
            @RequestBody Map<String, Object> requestBody) {
        logger.info("更新文档状态: datasetId={}, action={}", datasetId, action);
        return difyProxyService.updateDocumentStatus(datasetId, action, requestBody);
    }
}
