/**
 * Tool definitions
 *
 * Tool interface used by agents and workflows.
 * Provides a universal interface for AI systems to interact with tools.
 */

import { z } from 'zod'
import { ExecutionError } from '../base/errors'
import type { ExecutionContext } from '../base/types'
import type { IterationContext } from '../agent/core/types'

/**
 * Options for tool execution
 * Provides named parameters for better API clarity and extensibility
 */
export interface ToolExecutionOptions {
  /** Tool input (validated against inputSchema before execution) */
  input: unknown

  /** Execution context with multi-tenant isolation and observability (optional for simple tools, required for platform/integration tools) */
  executionContext?: ExecutionContext

  /** Full iteration context for advanced tools (provides access to memoryManager, toolRegistry, logger, etc.) */
  iterationContext?: IterationContext

  /** Abort signal for timeout/cancellation -- forward to fetch() calls for clean cancellation */
  signal?: AbortSignal
}

/**
 * Tool interface for AI systems
 *
 * Used by:
 * - Agents: For agentic tool use (reasoning loop selects and executes tools)
 * - Workflows: For workflow step tool invocation (future)
 * - Platform tools: createApprovalTool(), createSchedulerTool()
 * - Integration tools: External API calls (Gmail, Slack, etc.)
 */
export interface Tool {
  // Required fields
  name: string // Unique identifier (e.g., 'web_search', 'calculator')
  description: string // What the tool does (used by LLM for selection)

  // I/O validation (both required for complete type safety)
  inputSchema: z.ZodSchema // Input validation schema
  outputSchema: z.ZodSchema // Output validation schema

  // Execution
  execute: (options: ToolExecutionOptions) => Promise<unknown>

  // Timeout (optional) -- per-tool override in ms, defaults to DEFAULT_TOOL_TIMEOUT (300_000 / 5min) in executor
  timeout?: number
}

/**
 * Tool definition (for LLM communication)
 * Universal format for tool specifications sent to LLMs
 */
export interface ToolDefinition {
  name: string // Unique identifier
  description: string // LLM-readable purpose
  inputSchema: unknown // JSON Schema
}

/**
 * Tooling error types
 * Used across platform tools and integration tools
 */
export type ToolingErrorType =
  // Platform tool errors
  | 'service_unavailable'
  | 'permission_denied'
  | 'platform_internal'

  // Integration tool errors
  | 'adapter_not_found'
  | 'method_not_found'
  | 'tool_not_found'
  | 'credentials_missing'
  | 'credentials_invalid'
  | 'rate_limit_exceeded'
  | 'server_unavailable'
  | 'auth_error'
  | 'api_error'
  | 'validation_error'
  | 'network_error'
  | 'timeout_error'
  | 'unknown_error'

/**
 * Tooling error class
 * Provides structured error information for tool failures across all tool types
 *
 * Severity mapping:
 * - critical: credentials_missing, credentials_invalid, permission_denied, auth_error,
 *            adapter_not_found, method_not_found, tool_not_found
 * - info: validation_error
 * - warning: All other types (retryable transient errors)
 *
 * Category: tool (tool execution errors)
 */
export class ToolingError extends ExecutionError {
  readonly type = 'tooling_error' as const
  readonly category = 'tool' as const

  constructor(
    public readonly errorType: ToolingErrorType,
    message: string,
    public readonly details?: unknown
  ) {
    super(message, { type: errorType, details })
  }

  /**
   * Derive severity based on error type
   */
  get severity(): 'critical' | 'warning' | 'info' {
    // Critical: Authentication, authorization, and configuration errors
    if (
      [
        'credentials_missing',
        'credentials_invalid',
        'permission_denied',
        'auth_error',
        'adapter_not_found',
        'method_not_found',
        'tool_not_found'
      ].includes(this.errorType)
    ) {
      return 'critical'
    }

    // Info: Validation errors (user input errors)
    if (this.errorType === 'validation_error') {
      return 'info'
    }

    // Warning: Transient failures (retryable)
    return 'warning'
  }

  /**
   * Check if error is retryable
   */
  override isRetryable(): boolean {
    return [
      'service_unavailable',
      'rate_limit_exceeded',
      'api_error',
      'network_error',
      'timeout_error',
      'server_unavailable'
    ].includes(this.errorType)
  }

  /**
   * Convert to JSON for logging
   */
  toJSON() {
    return {
      name: this.name,
      type: this.errorType,
      message: this.message,
      severity: this.severity,
      category: this.category,
      details: this.details
    }
  }
}

// Factory functions for common error types

/** Platform tool errors */
export function serviceUnavailable(serviceName: string, details?: unknown): ToolingError {
  return new ToolingError('service_unavailable', `${serviceName} is unavailable`, details)
}

export function permissionDenied(operation: string): ToolingError {
  return new ToolingError('permission_denied', `Permission denied: ${operation}`)
}

/** Integration tool errors */
export function adapterNotFound(adapterId: string): ToolingError {
  return new ToolingError('adapter_not_found', `Integration adapter not found: ${adapterId}`)
}

export function methodNotFound(methodName: string): ToolingError {
  return new ToolingError('method_not_found', `Method not found: ${methodName}`)
}

export function toolNotFound(toolName: string): ToolingError {
  return new ToolingError('tool_not_found', `Tool not found: ${toolName}`)
}

export function credentialsMissing(integrationName: string): ToolingError {
  return new ToolingError('credentials_missing', `No credentials found for ${integrationName}`)
}

export function credentialsInvalid(integrationName: string): ToolingError {
  return new ToolingError('credentials_invalid', `Credentials expired or invalid for ${integrationName}`)
}

export function rateLimitExceeded(service: string): ToolingError {
  return new ToolingError('rate_limit_exceeded', `Rate limit exceeded for ${service}`)
}

export function serverUnavailable(serverName: string): ToolingError {
  return new ToolingError('server_unavailable', `${serverName} is unavailable`)
}

export function authError(message: string): ToolingError {
  return new ToolingError('auth_error', message)
}

export function apiError(message: string, details?: unknown): ToolingError {
  return new ToolingError('api_error', message, details)
}

export function validationError(message: string): ToolingError {
  return new ToolingError('validation_error', message)
}

export function networkError(message: string): ToolingError {
  return new ToolingError('network_error', message)
}

export function timeoutError(operation: string): ToolingError {
  return new ToolingError('timeout_error', `Operation timed out: ${operation}`)
}

export function unknownError(message: string, details?: unknown): ToolingError {
  return new ToolingError('unknown_error', message, details)
}
