package com.gzzm.lobster.tool;

import com.gzzm.lobster.common.ToolCategory;
import com.gzzm.lobster.common.ToolResultStatus;
import com.gzzm.lobster.common.ToolRiskLevel;
import com.gzzm.lobster.identity.UserContext;
import com.gzzm.lobster.llm.ToolCall;
import org.junit.Before;
import org.junit.Test;

import java.lang.reflect.Field;
import java.util.Collections;

import static org.junit.Assert.*;

public class ToolExecutorDispatcherTest {

    private ToolExecutorDispatcher dispatcher;
    private ToolRegistry registry;
    private ToolPermissionChecker permissionChecker;
    private ToolRateLimiter rateLimiter;
    private ToolAuditLogger auditLogger;

    private UserContext user;
    private ToolContext ctx;

    @Before
    public void setup() throws Exception {
        dispatcher = new ToolExecutorDispatcher();
        registry = new ToolRegistry();
        permissionChecker = new ToolPermissionChecker();
        rateLimiter = new ToolRateLimiter();
        auditLogger = new ToolAuditLogger() {
            @Override public void record(ToolContext ctx, String toolName, java.util.Map<String, Object> args, String r, int d) { /* no-op */ }
        };
        inject("toolRegistry", registry);
        inject("permissionChecker", permissionChecker);
        inject("rateLimiter", rateLimiter);
        inject("auditLogger", auditLogger);
        user = new UserContext("u1", "ext", "dept", "org", "张三", Collections.<String>emptySet());
        ctx = new ToolContext(user, "th_1", "run_1", "id1", "echo");

        BuiltinToolDefinition def = BuiltinToolDefinition.builder()
                .name("echo")
                .category(ToolCategory.WORKSPACE)
                .risk(ToolRiskLevel.READ_ONLY)
                .description("echo")
                .inputSchema(Collections.emptyMap())
                .build();
        registry.register(def, (c, args) -> ToolResult.ok("pong", null));
    }

    @Test
    public void unknownToolReturnsError() {
        ToolResult r = dispatcher.dispatch(ctx, new ToolCall("id", "no_such_tool", "{}"));
        assertEquals(ToolResultStatus.error, r.getStatus());
    }

    @Test
    public void registeredToolExecutes() {
        ToolResult r = dispatcher.dispatch(ctx, new ToolCall("id", "echo", "{}"));
        assertEquals(ToolResultStatus.ok, r.getStatus());
    }

    @Test
    public void badJsonArgsReturnsError() {
        ToolResult r = dispatcher.dispatch(ctx, new ToolCall("id", "echo", "not json"));
        assertEquals(ToolResultStatus.error, r.getStatus());
        assertTrue(r.getMessage().contains("invalid"));
    }

    private void inject(String fieldName, Object value) throws Exception {
        Field f = ToolExecutorDispatcher.class.getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(dispatcher, value);
    }
}
