/*
 * Copyright 2008-2026 Async-IO.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.atmosphere.ai.tool;

import java.util.Map;

/**
 * Executes an AI tool with the given arguments and returns a result.
 *
 * <p>Implementations are typically generated by reflection from
 * {@link org.atmosphere.ai.annotation.AiTool}-annotated methods, but can
 * also be created manually for dynamic tool registration.</p>
 */
@FunctionalInterface
public interface ToolExecutor {

    /**
     * Execute the tool.
     *
     * @param arguments the tool arguments as provided by the AI model,
     *                  keyed by parameter name
     * @return the result (will be serialized to JSON and sent back to the model)
     * @throws Exception if tool execution fails
     */
    Object execute(Map<String, Object> arguments) throws Exception;

    /**
     * Execute the tool with access to framework-scoped injectables. Used by the
     * reflective executor that {@link DefaultToolRegistry} builds from
     * {@link org.atmosphere.ai.annotation.AiTool}-annotated methods so the
     * method can declare parameter types like {@link org.atmosphere.ai.StreamingSession},
     * {@code AgentFleet}, or {@link org.atmosphere.cpr.AtmosphereResource} and
     * receive the live instances — no {@link ThreadLocal} shim required.
     *
     * <p>The default implementation delegates to {@link #execute(Map)} so
     * hand-written executors (e.g., MCP bridges, dynamic tools) keep working.
     * Framework-runtime bridges (Spring AI, LangChain4j, etc.) can opt in by
     * passing the active injectables map through at tool-dispatch time.</p>
     *
     * @param arguments   tool arguments from the AI model
     * @param injectables framework-scoped instances keyed by {@code Class<?>};
     *                    {@code null} is treated as an empty map
     * @return the result (serialized to JSON and sent back to the model)
     * @throws Exception if tool execution fails
     */
    default Object execute(Map<String, Object> arguments,
                           Map<Class<?>, Object> injectables) throws Exception {
        return execute(arguments);
    }
}
