/**
 * Example 19: Tool Wrapping and Enhancement
 *
 * This example demonstrates advanced tool composition patterns using tool wrapping.
 * It shows how to:
 * - Create enhanced versions of existing tools using clone()
 * - Extend tool output schemas with additional fields
 * - Implement decorator patterns for tool functionality
 * - Chain tool execution with pre/post processing
 * - Build composable tool architectures
 *
 * Key concepts:
 * - Tool cloning and enhancement
 * - Schema extension and composition
 * - Decorator pattern implementation
 * - Tool execution chaining
 * - Composable tool design patterns
 */

import { Client } from '@botpress/client'
import { z } from '@bpinternal/zui'
import chalk from 'chalk'
import { execute, Exit, Tool } from 'llmz'
import { box } from '../utils/box'

// Initialize Botpress client
const client = new Client({
  botId: process.env.BOTPRESS_BOT_ID!,
  token: process.env.BOTPRESS_TOKEN!,
})

// Exit condition to capture the final result
const exit = new Exit({
  name: 'exit',
  description: 'Exit the program',
  schema: z.object({
    result: z.number(),
  }),
})

// Original base tool with simple greeting functionality
// This demonstrates the tool that will be enhanced through wrapping
const normalTool = new Tool({
  name: 'greet',
  description: 'A tool that greets the user',
  input: z.object({
    greeting: z.string(),
  }),
  output: z.object({
    message: z.string(),
  }),
  async handler(input) {
    console.log(chalk.green('✓') + ` Original tool executed with input: ${input.greeting}`)
    return { message: `Hello, ${input.greeting}!` }
  },
})

// Enhanced tool created by wrapping the original tool
// This demonstrates the decorator pattern for tool enhancement
const wrappedTool = normalTool.clone({
  // Extend the output schema to include additional fields
  // This shows how to compose and extend existing schemas
  output: (schema) =>
    schema!.extend({
      added: z.number().describe('Tool confirmation number'),
    }),

  // Enhanced handler that calls the original tool and adds functionality
  async handler(input, ctx) {
    console.log(chalk.blue('✓') + ` Wrapped tool executed with input: ${input.greeting}`)

    // Execute the original tool to get its result
    // This demonstrates composition and delegation patterns
    const result = await normalTool.execute(input, ctx)

    // Return enhanced result with additional data
    // This shows how to augment tool outputs with new information
    return {
      message: `Wrapped tool executed with input: ${input.greeting}. Original message: ${result.message}`,
      added: 666, // Additional confirmation code
    }
  },
})

// Execute using the wrapped tool
const result = await execute({
  instructions: 'Greet the user and return the confirmation code',
  exits: [exit],

  // Use the wrapped tool instead of the original
  // The LLM will see the enhanced schema and functionality
  tools: [wrappedTool],
  client,
})

// Display the results showing the enhanced functionality
if (result.is(exit)) {
  console.log(
    box(
      [
        'The LLM wrote this code:',
        // Show the generated code that used the wrapped tool
        ...result.iteration.code!.split('\n'),
        '',
        'It then executed it and returned the result:',
        // Display the confirmation code from the wrapped tool
        chalk.cyan.bold(result.output.result.toString()),
      ],
      80
    )
  )
}
