package com.gzzm.lobster.api;

import com.gzzm.lobster.identity.UserContext;
import com.gzzm.lobster.identity.UserContextHolder;
import com.gzzm.lobster.oa.OaKnowledgeClient;
import com.gzzm.lobster.oa.OaKnowledgeScope;
import com.gzzm.platform.commons.Tools;
import net.cyan.arachne.HttpMethod;
import net.cyan.arachne.annotation.Service;
import net.cyan.nest.annotation.Inject;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * KbApi —— 知识库元数据 REST API / KB metadata REST API.
 *
 * <p>暴露：
 * <ul>
 *   <li>{@code GET  /ai/api/kb/scopes} —— 给 ChatComposer 的「知识库范围」气泡列表</li>
 *   <li>{@code POST /ai/api/kb/detail} —— 给引用气泡点击后弹出的详情抽屉用</li>
 * </ul>
 * 检索（search）仍只走「LLM 调 oa_search_knowledge 工具」的统一入口，引用气泡由 SSE 的
 * tool_result.data 推回前端，避免双通道导致行为分裂.
 *
 * <p>失败策略：listScopes 不可用返空 + warning（200 OK），让 UI 仍可使用全库默认；
 * detail 失败正常 throw（前端 drawer 显示错误，比静默假数据更安全）.
 */
@Service
public class KbApi {

    @Inject private OaKnowledgeClient oaKnowledgeClient;

    @Service(url = "/ai/api/kb/scopes", method = HttpMethod.all)
    public Map<String, Object> listScopes() {
        UserContext user = UserContextHolder.require();
        Map<String, Object> out = new LinkedHashMap<>();
        try {
            List<OaKnowledgeScope> scopes = oaKnowledgeClient.listScopes(user);
            List<Map<String, Object>> rows = new ArrayList<>();
            if (scopes != null) {
                for (OaKnowledgeScope s : scopes) {
                    Map<String, Object> row = new LinkedHashMap<>();
                    row.put("id", s.getId());
                    row.put("name", s.getName());
                    if (s.getDescription() != null) row.put("description", s.getDescription());
                    row.put("docCount", s.getDocCount());
                    rows.add(row);
                }
            }
            out.put("scopes", rows);
            return out;
        } catch (Throwable t) {
            try { Tools.log("[KbApi] listScopes failed; returning empty list", t); }
            catch (Throwable ignore) { /* ignore */ }
            out.put("scopes", Collections.emptyList());
            // 给前端透出原因便于调试，但 status 仍 200——不让一个上游故障把开关给禁了
            out.put("warning", "KB upstream not available: " + safeMsg(t));
            return out;
        }
    }

    /**
     * 取知识库条目详情 / Fetch KB entry detail by docId.
     *
     * <p>给前端引用气泡点击后的详情抽屉调用——避免暴露真实 KB endpoint 给浏览器，
     * 鉴权由 {@link UserContextHolder#require()} 管，KB 侧权限裁决靠 user 透传.
     *
     * <p>不复用 LLM 工具 {@code oa_get_knowledge_detail} —— 工具走 audit + LLM 上下文链路，
     * 这里是纯前端浏览，避免污染 LLM 调用统计.
     */
    @Service(url = "/ai/api/kb/detail", method = HttpMethod.post)
    public Map<String, Object> getDetail(String docId) throws Exception {
        UserContext user = UserContextHolder.require();
        if (docId == null || docId.trim().isEmpty()) {
            throw new IllegalArgumentException("docId required");
        }
        String content = oaKnowledgeClient.getDetail(user, docId.trim());
        Map<String, Object> out = new LinkedHashMap<>();
        out.put("docId", docId.trim());
        out.put("content", content == null ? "" : content);
        return out;
    }

    private static String safeMsg(Throwable t) {
        if (t == null) return "unknown";
        String m = t.getMessage();
        return m == null ? t.getClass().getSimpleName() : m;
    }
}
