import ChatTab
import ConversationServiceProvider
import Foundation
import JSONRPC
import ChatAPIService

public protocol ToolContextProvider {
    // MARK: insert_edit_into_file
    var chatTabInfo: ChatTabInfo { get }
    func updateFileEdits(by fileEdit: FileEdit) -> Void
    func notifyChangeTextDocument(fileURL: URL, content: String, version: Int) async throws
    func updateChatHistory(_ turnId: String, editAgentRounds: [AgentRound], fileEdits: [FileEdit])
}


public protocol ICopilotTool {
    /**
      * Invokes the Copilot tool with the given request.
      *  - Parameters:
      *      - request: The tool invocation request.
      *      - completion: Closure called with JSON-RPC response when tool execution completes.
      *      - contextProvider: Optional provider that supplies additional context information
      *                         needed for tool execution, such as chat tab data and file editing capabilities.
      *  - Returns: Boolean indicating if the tool call has completed. True if the tool call is completed, false otherwise.
     */
    func invokeTool(
        _ request: InvokeClientToolRequest,
        completion: @escaping (AnyJSONRPCResponse) -> Void,
        contextProvider: ToolContextProvider?
    ) -> Bool
}

extension ICopilotTool {
    /**
     * Completes a tool response.
     * - Parameters:
     *   - request: The original tool invocation request.
     *   - status: The completion status of the tool execution (success, error, or cancelled).
     *   - response: The string value to include in the response content.
     *   - completion: The completion handler to call with the response.
     */
    func completeResponse(
        _ request: InvokeClientToolRequest,
        status: ToolInvocationStatus = .success,
        response: String = "",
        completion: @escaping (AnyJSONRPCResponse) -> Void
    ) {
        completeResponses(
            request,
            status: status,
            responses: [response],
            completion: completion
        )
    }

    ///
    /// Completes a tool response with multiple data entries.
    /// - Parameters:
    ///   - request: The original tool invocation request.
    ///   - status: The completion status of the tool execution (success, error, or cancelled).
    ///   - responses: Array of string values to include in the response content.
    ///   - completion: The completion handler to call with the response.
    ///
    func completeResponses(
        _ request: InvokeClientToolRequest,
        status: ToolInvocationStatus = .success,
        responses: [String],
        completion: @escaping (AnyJSONRPCResponse) -> Void
    ) {
        let toolResult = LanguageModelToolResult(status: status, content: responses.map { response in
            LanguageModelToolResult.Content(value: response)
        })
        let jsonResult = try? JSONEncoder().encode(toolResult)
        let jsonValue = (try? JSONDecoder().decode(JSONValue.self, from: jsonResult ?? Data())) ?? JSONValue.null
        completion(
            AnyJSONRPCResponse(
                id: request.id,
                result: JSONValue.array([
                    jsonValue,
                    JSONValue.null,
                ])
            )
        )
    }
}

extension ChatService: ToolContextProvider {
    public func updateChatHistory(_ turnId: String, editAgentRounds: [AgentRound], fileEdits: [FileEdit] = []) {
        appendToolCallHistory(turnId: turnId, editAgentRounds: editAgentRounds, fileEdits: fileEdits)
    }
}
