package com.agent.management.rag.kb;

import com.agent.management.model.entity.RagKnowledgeSourceBinding;
import com.agent.management.rag.model.RagSourceType;
import com.agent.management.repository.RagKnowledgeSourceBindingRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class RagKnowledgeBaseConfigService {
    private final RagKnowledgeSourceBindingRepository bindings;
    private final ObjectMapper mapper;

    public List<RagKnowledgeSourceBinding> listBindings(Long knowledgeBaseId) {
        return bindings.findByKnowledgeBaseIdOrderByPriorityAsc(knowledgeBaseId);
    }

    public RagKnowledgeSourceBinding updateConfig(Long knowledgeBaseId, Long bindingId, Map<String, Object> config) {
        RagKnowledgeSourceBinding binding = bindings.findById(bindingId)
                .filter(item -> knowledgeBaseId.equals(item.getKnowledgeBaseId()))
                .orElseThrow(() -> new IllegalArgumentException("knowledge base binding does not exist: " + bindingId));
        validateAuthorization(binding, config);
        try {
            binding.setConfigJson(mapper.writeValueAsString(config == null ? Map.of() : config));
            return bindings.save(binding);
        } catch (Exception e) {
            throw new IllegalArgumentException("invalid binding config: " + e.getMessage(), e);
        }
    }

    /**
     * 按 (knowledgeBaseId, sourceType, sourceId) 查找绑定：
     * 存在则更新 configJson；不存在则新建绑定后再写入 configJson。
     * 用于 RAG 治理页"应用审核后的授权配置"：当用户尚未在知识库与数据源之间建立绑定时，
     * 自动创建一条绑定记录，避免"没有匹配的数据源绑定"错误阻断治理流程。
     */
    public RagKnowledgeSourceBinding upsertBySource(Long knowledgeBaseId, RagSourceType sourceType,
                                                     String sourceId, Map<String, Object> config) {
        if (sourceType == null) {
            throw new IllegalArgumentException("sourceType is required");
        }
        if (sourceId == null || sourceId.isBlank()) {
            throw new IllegalArgumentException("sourceId is required");
        }
        RagKnowledgeSourceBinding binding = bindings
                .findByKnowledgeBaseIdAndSourceTypeAndSourceId(knowledgeBaseId, sourceType, sourceId)
                .orElseGet(() -> {
                    RagKnowledgeSourceBinding created = new RagKnowledgeSourceBinding();
                    created.setKnowledgeBaseId(knowledgeBaseId);
                    created.setSourceType(sourceType);
                    created.setSourceId(sourceId);
                    return created;
                });
        validateAuthorization(binding, config);
        try {
            binding.setConfigJson(mapper.writeValueAsString(config == null ? Map.of() : config));
            return bindings.save(binding);
        } catch (Exception e) {
            throw new IllegalArgumentException("invalid binding config: " + e.getMessage(), e);
        }
    }

    private static void validateAuthorization(RagKnowledgeSourceBinding binding, Map<String,Object> config) {
        if (config == null || !"AUTO_GENERATE".equals(String.valueOf(config.get("retrievalMode")))) return;
        String key = binding.getSourceType() == RagSourceType.GRAPH ? "allowedLabels" : null;
        if (key != null && (!(config.get(key) instanceof List<?> values) || values.isEmpty()))
            throw new IllegalArgumentException("automatic generation requires a non-empty explicit " + key);
    }
}
