// ABOUTME: Adapter that wraps MCP tools to integrate with Lace's Tool base class
// ABOUTME: Uses MCP SDK client for tool execution, converts schemas from JSON to Zod

import { z, ZodType } from 'zod';
import { Tool } from '@lace/agent/tools/tool';
import type { ToolResult, ToolContext, ContentBlock } from '@lace/agent/tools/types';
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
import type { MCPTool } from '@lace/agent/config/mcp-types';

/**
 * Converts MCP JSON Schema to Zod schema
 * Simplified converter - handles basic types needed for MCP tools
 */
interface JsonSchemaProperty {
  type: string;
  description?: string;
  items?: JsonSchemaProperty;
}

interface JsonSchema {
  type: string;
  properties?: Record<string, JsonSchemaProperty>;
  required?: string[];
}

function jsonSchemaToZod(schema: JsonSchema): ZodType {
  if (schema.type === 'object') {
    const shape: Record<string, ZodType> = {};

    for (const [key, prop] of Object.entries(schema.properties || {})) {
      const propSchema = prop;

      let zodType: ZodType;

      if (propSchema.type === 'string') {
        zodType = z.string();
      } else if (propSchema.type === 'number') {
        zodType = z.number();
      } else if (propSchema.type === 'integer') {
        zodType = z.number().int();
      } else if (propSchema.type === 'boolean') {
        zodType = z.boolean();
      } else if (propSchema.type === 'array') {
        const itemType = propSchema.items ? jsonSchemaToZod(propSchema.items) : z.unknown();
        zodType = z.array(itemType);
      } else {
        // Fallback for complex types
        zodType = z.unknown();
      }

      // Add description if present
      if (propSchema.description) {
        zodType = zodType.describe(propSchema.description);
      }

      // Handle required fields
      if (!schema.required?.includes(key)) {
        zodType = zodType.optional();
      }

      shape[key] = zodType;
    }

    return z.object(shape);
  }

  // Fallback for non-object schemas
  return z.unknown();
}

export class MCPToolAdapter extends Tool {
  name: string;
  description: string;
  schema: ZodType;

  constructor(
    private mcpTool: MCPTool,
    private serverId: string,
    private client: Client
  ) {
    super();
    this.name = `${serverId}/${mcpTool.name}`;
    this.description = mcpTool.description || `MCP tool: ${mcpTool.name}`;
    this.schema = mcpTool.inputSchema
      ? jsonSchemaToZod(mcpTool.inputSchema as JsonSchema)
      : z.object({}); // Safe fallback for tools without input schema
  }

  // TODO(D2): MCP session keying + identity
  protected async executeValidated(
    args: Record<string, unknown>,
    _context?: ToolContext
  ): Promise<ToolResult> {
    try {
      // Use MCP SDK's high-level callTool method
      const result = await this.client.callTool({
        name: this.mcpTool.name,
        arguments: args,
      });

      // Convert MCP result to Lace ToolResult format
      if (result.isError) {
        const contentArray = Array.isArray(result.content) ? result.content : [result.content];
        return this.createError(
          `MCP tool error: ${contentArray.map((c: unknown) => (c as { text?: string }).text || '').join(' ')}`,
          { toolName: this.mcpTool.name }
        );
      }

      // Convert MCP content blocks to Lace format
      const contentArray = Array.isArray(result.content) ? result.content : [result.content];
      const content: ContentBlock[] = contentArray.map((block: unknown) => {
        const typedBlock = block as {
          type: string;
          text?: string;
          data?: string;
          resource?: { uri?: string };
        };

        if (typedBlock.type === 'text') {
          return { type: 'text' as const, text: typedBlock.text || '' };
        } else if (typedBlock.type === 'image') {
          return {
            type: 'image' as const,
            data: typedBlock.data,
          };
        } else if (typedBlock.type === 'resource') {
          return {
            type: 'resource' as const,
            uri: typedBlock.resource?.uri,
          };
        } else {
          // Fallback for unknown content types
          return {
            type: 'text' as const,
            text: JSON.stringify(block),
          };
        }
      });

      return {
        content,
        status: 'completed',
        metadata: {
          toolName: this.mcpTool.name,
          serverId: this.serverId,
        },
      };
    } catch (error) {
      return this.createError(
        `Failed to execute MCP tool: ${error instanceof Error ? error.message : 'Unknown error'}`,
        { toolName: this.mcpTool.name, serverId: this.serverId }
      );
    }
  }
}
