package tech.easyflow.approval.support;

import org.junit.Test;

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

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;

/**
 * {@link ApprovalSnapshotProjection} 响应脱敏契约测试。
 */
public class ApprovalSnapshotProjectionTest {

    /**
     * 验证 Skill 审批仅保留标准包和 Tool 绑定摘要，不返回正文、资源正文或 MCP 连接信息。
     */
    @Test
    public void shouldProjectSkillSnapshotToSafeSummary() {
        Map<String, Object> snapshot = new LinkedHashMap<>();
        snapshot.put("previousStatus", "DRAFT");
        snapshot.put("resourceSnapshot", Map.of(
                "schemaVersion", 2,
                "name", "contract-review",
                "description", "合同审查",
                "skillContent", "# private instructions",
                "resources", List.of(Map.of(
                        "path", "references/private.md",
                        "content", "private reference",
                        "contentRef", "internal-ref")),
                "packageHash", "package-hash",
                "contentSnapshotHash", "content-hash",
                "platformToolBindings", Map.of(
                        "bindings", List.of(Map.of(
                                "toolType", "MCP",
                                "targetId", 9,
                                "displayName", "GitHub",
                                "toolCount", 2,
                                "mcpToolManifestHash", "manifest-hash",
                                "resourceSummary", Map.of(
                                        "title", "GitHub",
                                        "baseUrl", "https://internal.example?token=secret",
                                        "requestHeaders", Map.of("Authorization", "secret")),
                                "mcpToolManifest", List.of(Map.of(
                                        "name", "search",
                                        "inputSchema", Map.of("token", "secret"))),
                                "resourceSnapshot", Map.of(
                                        "configJson", "{\"env\":{\"TOKEN\":\"secret\"}}",
                                        "headers", Map.of("Authorization", "secret"),
                                        "environment", Map.of("TOKEN", "secret")))),
                        "snapshotHash", "tools-hash"),
                "toolBindingsHash", "tools-hash",
                "snapshotHash", "aggregate-hash"));

        Map<String, Object> projected = ApprovalSnapshotProjection.project("SKILL", snapshot);
        Map<?, ?> resource = (Map<?, ?>) projected.get("resourceSnapshot");
        Map<?, ?> platformBindings = (Map<?, ?>) resource.get("platformToolBindings");
        Map<?, ?> binding = (Map<?, ?>) ((List<?>) platformBindings.get("bindings")).get(0);

        assertEquals("contract-review", resource.get("name"));
        assertEquals("合同审查", resource.get("description"));
        assertEquals("aggregate-hash", resource.get("snapshotHash"));
        assertEquals(1, resource.get("resourceCount"));
        assertEquals("manifest-hash", binding.get("mcpToolManifestHash"));
        assertEquals(2, binding.get("toolCount"));
        assertEquals(1, binding.get("manifestToolCount"));
        assertFalse(resource.containsKey("skillContent"));
        assertFalse(resource.containsKey("resources"));
        assertFalse(binding.containsKey("mcpToolManifest"));
        assertFalse(binding.containsKey("resourceSnapshot"));
        Map<?, ?> bindingSummary = (Map<?, ?>) binding.get("resourceSummary");
        assertEquals("GitHub", bindingSummary.get("title"));
        assertFalse(bindingSummary.containsKey("baseUrl"));
        assertFalse(bindingSummary.containsKey("requestHeaders"));
        assertTrue(serialize(projected).indexOf("secret") < 0);
    }

    /**
     * 验证 Agent 审批保留绑定摘要与 hash，同时递归移除配置正文和嵌套 Skill 运行快照。
     */
    @Test
    public void shouldProjectAgentSnapshotToSafeSummary() {
        Map<String, Object> resourceSnapshot = new LinkedHashMap<>();
        resourceSnapshot.put("id", 7);
        resourceSnapshot.put("name", "审查 Agent");
        resourceSnapshot.put("description", "用于审查合同");
        resourceSnapshot.put("promptConfigJson", Map.of("systemPrompt", "private prompt"));
        resourceSnapshot.put("modelConfigJson", Map.of("apiKey", "secret"));
        resourceSnapshot.put("basicSummary", Map.of("name", "审查 Agent", "status", 1));
        resourceSnapshot.put("skillBindings", List.of(Map.of(
                "skillId", 21,
                "sortNo", 0,
                "resourceSummary", Map.of(
                        "displayName", "合同审查",
                        "snapshotHash", "skill-hash",
                        "textResourceCount", 3),
                "resourceSnapshot", Map.of(
                        "skillContent", "private skill",
                        "resources", List.of(Map.of("content", "private reference")),
                        "source", "easyflow://internal"))));

        Map<String, Object> projected = ApprovalSnapshotProjection.project(
                "agent", Map.of("resourceSnapshot", resourceSnapshot));
        Map<?, ?> resource = (Map<?, ?>) projected.get("resourceSnapshot");
        Map<?, ?> binding = (Map<?, ?>) ((List<?>) resource.get("skillBindings")).get(0);
        Map<?, ?> summary = (Map<?, ?>) binding.get("resourceSummary");

        assertEquals("审查 Agent", resource.get("name"));
        assertEquals("合同审查", summary.get("displayName"));
        assertEquals("skill-hash", summary.get("snapshotHash"));
        assertEquals(3, summary.get("textResourceCount"));
        assertFalse(resource.containsKey("promptConfigJson"));
        assertFalse(resource.containsKey("modelConfigJson"));
        assertFalse(binding.containsKey("resourceSnapshot"));
        assertTrue(serialize(projected).indexOf("private skill") < 0);
        assertTrue(serialize(projected).indexOf("easyflow://internal") < 0);
    }

    /**
     * 验证历史审批资源保持兼容，但详情响应使用独立深复制 Map。
     */
    @Test
    public void shouldKeepLegacyResourceSnapshotsCompatible() {
        Map<String, Object> snapshot = Map.of(
                "resourceSnapshot", Map.of("title", "流程", "content", "workflow source"));

        Map<String, Object> projected = ApprovalSnapshotProjection.project("WORKFLOW", snapshot);

        assertNotSame(snapshot, projected);
        assertEquals(snapshot, projected);
    }

    /**
     * 将测试对象转成稳定字符串，便于断言敏感字面值未出现在任意嵌套层级。
     *
     * @param value 待检查对象
     * @return 对象字符串
     */
    private String serialize(Object value) {
        return String.valueOf(value);
    }
}
