import { JSONSchema7 } from 'json-schema';
import { randomUUID } from 'crypto';
import { createTool, createSuccessResult, createErrorResult } from '../../core/tool-framework.js';
import { ToolRegistration, RequestContext } from '../../core/types.js';

/**
 * Process Automation Module Tools - 12-Factor MCP Implementation
 * 
 * Provides comprehensive workflow automation with:
 * - Multiple trigger types (manual, schedule, event, webhook, condition, chain)
 * - Various activity types (tool, human, agent, conditional, loop, parallel, external)
 * - Error handling and retry policies
 * - Execution tracking and logging
 * - Template-based process creation
 */

// Input type interfaces
export interface CreateProcessInput {
  name: string;
  description?: string;
  version?: string;
  persona?: string;
  category?: string;
  tags?: string[];
  triggers?: Array<{
    type: 'manual' | 'schedule' | 'event' | 'webhook' | 'condition' | 'chain';
    name: string;
    enabled?: boolean;
    config: any;
  }>;
  activities: Array<{
    id: string;
    type: 'tool' | 'human' | 'agent' | 'conditional' | 'loop' | 'parallel' | 'external';
    name: string;
    description?: string;
    config: any;
    retryPolicy?: {
      maxRetries: number;
      backoffMultiplier?: number;
      initialDelay?: number;
    };
    timeout?: number;
    required?: boolean;
  }>;
  variables?: Record<string, any>;
  onSuccess?: any[];
  onFailure?: any[];
}

export interface ExecuteProcessInput {
  processId: string;
  variables?: Record<string, any>;
  triggeredBy?: string;
  triggerType?: string;
}

export interface ListProcessesInput {
  category?: string;
  persona?: string;
  tags?: string[];
  isActive?: boolean;
}

export interface ListExecutionsInput {
  processId?: string;
  status?: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
  limit?: number;
  offset?: number;
}

export interface SuggestTriggersInput {
  processName: string;
  activities: Array<{
    type: string;
    name: string;
    toolName?: string;
  }>;
  persona?: string;
}

export interface CreateFromTemplateInput {
  templateId: string;
  name: string;
  description?: string;
  variables?: Record<string, any>;
}

/**
 * Create a new automation process
 */
const createProcessTool = createTool<CreateProcessInput, any>({
  name: 'create_process',
  description: 'Create a new automation process with triggers and activities',
  category: 'process-automation',
  inputSchema: {
    type: 'object',
    properties: {
      name: {
        type: 'string',
        description: 'Process name',
        minLength: 1,
        maxLength: 200
      },
      description: {
        type: 'string',
        description: 'Process description',
        maxLength: 1000
      },
      version: {
        type: 'string',
        description: 'Process version',
        default: '1.0.0',
        pattern: '^\\d+\\.\\d+\\.\\d+$'
      },
      persona: {
        type: 'string',
        description: 'Persona type for the process'
      },
      category: {
        type: 'string',
        description: 'Process category'
      },
      tags: {
        type: 'array',
        items: { type: 'string' },
        description: 'Process tags for organization',
        maxItems: 20
      },
      triggers: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            type: {
              type: 'string',
              enum: ['manual', 'schedule', 'event', 'webhook', 'condition', 'chain']
            },
            name: { type: 'string' },
            enabled: { type: 'boolean', default: true },
            config: { type: 'object' }
          },
          required: ['type', 'name', 'config']
        },
        description: 'Process triggers',
        minItems: 1
      },
      activities: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            id: { type: 'string' },
            type: {
              type: 'string',
              enum: ['tool', 'human', 'agent', 'conditional', 'loop', 'parallel', 'external']
            },
            name: { type: 'string' },
            description: { type: 'string' },
            config: { type: 'object' },
            retryPolicy: {
              type: 'object',
              properties: {
                maxRetries: { type: 'integer', minimum: 0 },
                backoffMultiplier: { type: 'number' },
                initialDelay: { type: 'integer' }
              }
            },
            timeout: { type: 'integer', minimum: 1000 },
            required: { type: 'boolean', default: true }
          },
          required: ['id', 'type', 'name', 'config']
        },
        description: 'Process activities to execute',
        minItems: 1
      },
      variables: {
        type: 'object',
        description: 'Process variables'
      },
      onSuccess: {
        type: 'array',
        description: 'Activities to run on success'
      },
      onFailure: {
        type: 'array',
        description: 'Activities to run on failure'
      }
    },
    required: ['name', 'activities'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: CreateProcessInput, context: RequestContext) {
    try {
      const processId = randomUUID();
      const now = Date.now();

      // Check for duplicate process names
      const existingProcess = await context.db.get(
        'SELECT id FROM process_definitions WHERE name = ? AND project_id = ? AND is_active = TRUE',
        [input.name, context.projectId || 'default']
      );

      if (existingProcess.success && existingProcess.data) {
        return createErrorResult({
          code: 'DUPLICATE_RESOURCE',
          message: 'An active process with this name already exists',
          category: 'validation'
        });
      }

      // Start transaction for process creation
      await context.db.transaction(async (tx) => {
        // Create process definition
        await tx.run(
          `INSERT INTO process_definitions 
           (id, project_id, name, description, version, persona, category, tags, 
            variables, on_success, on_failure, is_active, created_by, created_at, updated_at) 
           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            processId,
            context.projectId || 'default',
            input.name,
            input.description || '',
            input.version || '1.0.0',
            input.persona || null,
            input.category || null,
            JSON.stringify(input.tags || []),
            JSON.stringify(input.variables || {}),
            input.onSuccess ? JSON.stringify(input.onSuccess) : null,
            input.onFailure ? JSON.stringify(input.onFailure) : null,
            true,
            context.userId || 'system',
            now,
            now
          ]
        );

        // Create activities
        for (let i = 0; i < input.activities.length; i++) {
          const activity = input.activities[i];
          await tx.run(
            `INSERT INTO process_activities 
             (id, process_id, activity_order, activity_id, type, name, description, 
              config, retry_policy, timeout, required, created_at) 
             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
            [
              randomUUID(),
              processId,
              i,
              activity.id,
              activity.type,
              activity.name,
              activity.description || '',
              JSON.stringify(activity.config),
              activity.retryPolicy ? JSON.stringify(activity.retryPolicy) : null,
              activity.timeout || null,
              activity.required !== false,
              now
            ]
          );
        }

        // Create triggers if provided
        if (input.triggers) {
          for (const trigger of input.triggers) {
            await tx.run(
              `INSERT INTO process_triggers 
               (id, process_id, trigger_id, type, name, enabled, config, created_at, updated_at) 
               VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
              [
                randomUUID(),
                processId,
                randomUUID(),
                trigger.type,
                trigger.name,
                trigger.enabled !== false,
                JSON.stringify(trigger.config),
                now,
                now
              ]
            );
          }
        } else {
          // Create default manual trigger
          await tx.run(
            `INSERT INTO process_triggers 
             (id, process_id, trigger_id, type, name, enabled, config, created_at, updated_at) 
             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
            [
              randomUUID(),
              processId,
              randomUUID(),
              'manual',
              'Manual Trigger',
              true,
              JSON.stringify({}),
              now,
              now
            ]
          );
        }
      });

      return createSuccessResult({
        process: {
          id: processId,
          name: input.name,
          description: input.description || '',
          version: input.version || '1.0.0',
          persona: input.persona || null,
          category: input.category || null,
          tags: input.tags || [],
          activityCount: input.activities.length,
          triggerCount: input.triggers?.length || 1,
          createdAt: new Date(now).toISOString()
        },
        message: `Process "${input.name}" created successfully`,
        nextSteps: [
          'Test the process with manual execution',
          'Configure additional triggers if needed',
          'Monitor execution results'
        ]
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to create process: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Execute a process
 */
const executeProcessTool = createTool<ExecuteProcessInput, any>({
  name: 'execute_process',
  description: 'Execute an automation process manually',
  category: 'process-automation',
  inputSchema: {
    type: 'object',
    properties: {
      processId: {
        type: 'string',
        description: 'Process ID to execute',
        pattern: '^[a-zA-Z0-9-]+$'
      },
      variables: {
        type: 'object',
        description: 'Variables to pass to the process'
      },
      triggeredBy: {
        type: 'string',
        description: 'Who/what triggered the execution'
      },
      triggerType: {
        type: 'string',
        description: 'Type of trigger'
      }
    },
    required: ['processId'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: ExecuteProcessInput, context: RequestContext) {
    try {
      // Get process definition
      const processResult = await context.db.get(
        'SELECT * FROM process_definitions WHERE id = ? AND project_id = ? AND is_active = TRUE',
        [input.processId, context.projectId || 'default']
      );

      if (!processResult.success || !processResult.data) {
        return createErrorResult({
          code: 'RESOURCE_NOT_FOUND',
          message: 'Process not found or inactive',
          category: 'validation'
        });
      }

      const process = processResult.data;
      const executionId = randomUUID();
      const now = Date.now();

      // Merge process variables with input variables
      const processVariables = JSON.parse(process.variables || '{}');
      const executionVariables = { ...processVariables, ...input.variables };

      // Create execution record
      const execResult = await context.db.run(
        `INSERT INTO process_executions 
         (id, process_id, project_id, process_version, status, triggered_by, 
          trigger_type, variables, started_at, created_at) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          executionId,
          input.processId,
          context.projectId || 'default',
          process.version,
          'pending',
          input.triggeredBy || context.userId || 'manual',
          input.triggerType || 'manual',
          JSON.stringify(executionVariables),
          now,
          now
        ]
      );

      if (!execResult.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to create execution record',
          category: 'system'
        });
      }

      // Log execution start
      await context.db.run(
        `INSERT INTO process_execution_logs 
         (id, execution_id, timestamp, level, message) 
         VALUES (?, ?, ?, ?, ?)`,
        [
          randomUUID(),
          executionId,
          now,
          'info',
          `Process execution started for "${process.name}"`
        ]
      );

      // Note: Actual execution would be handled by a background worker
      // This is just creating the execution record

      return createSuccessResult({
        execution: {
          id: executionId,
          processId: input.processId,
          processName: process.name,
          status: 'pending',
          triggeredBy: input.triggeredBy || context.userId || 'manual',
          startedAt: new Date(now).toISOString()
        },
        message: `Process execution started successfully`,
        note: 'Execution will be processed by the automation engine'
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to execute process: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * List processes
 */
const listProcessesTool = createTool<ListProcessesInput, any>({
  name: 'list_processes',
  description: 'List all automation processes',
  category: 'process-automation',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      category: {
        type: 'string',
        description: 'Filter by category'
      },
      persona: {
        type: 'string',
        description: 'Filter by persona'
      },
      tags: {
        type: 'array',
        items: { type: 'string' },
        description: 'Filter by tags'
      },
      isActive: {
        type: 'boolean',
        description: 'Filter by active status',
        default: true
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: ListProcessesInput, context: RequestContext) {
    try {
      let query = 'SELECT * FROM process_definitions WHERE project_id = ?';
      const params: any[] = [context.projectId || 'default'];

      if (input.isActive !== undefined) {
        query += ' AND is_active = ?';
        params.push(input.isActive);
      }

      if (input.category) {
        query += ' AND category = ?';
        params.push(input.category);
      }

      if (input.persona) {
        query += ' AND persona = ?';
        params.push(input.persona);
      }

      query += ' ORDER BY created_at DESC';

      const result = await context.db.query(query, params);

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to list processes',
          category: 'system'
        });
      }

      const processes = [];
      for (const proc of result.data || []) {
        // Filter by tags if specified
        if (input.tags && input.tags.length > 0) {
          const processTags = JSON.parse(proc.tags || '[]');
          if (!input.tags.some(tag => processTags.includes(tag))) {
            continue;
          }
        }

        // Get trigger count
        const triggerResult = await context.db.get(
          'SELECT COUNT(*) as count FROM process_triggers WHERE process_id = ?',
          [proc.id]
        );

        // Get activity count
        const activityResult = await context.db.get(
          'SELECT COUNT(*) as count FROM process_activities WHERE process_id = ?',
          [proc.id]
        );

        processes.push({
          id: proc.id,
          name: proc.name,
          description: proc.description,
          version: proc.version,
          category: proc.category,
          persona: proc.persona,
          tags: JSON.parse(proc.tags || '[]'),
          isActive: proc.is_active,
          triggerCount: triggerResult.data?.count || 0,
          activityCount: activityResult.data?.count || 0,
          createdAt: new Date(proc.created_at).toISOString(),
          updatedAt: new Date(proc.updated_at).toISOString()
        });
      }

      return createSuccessResult({
        processes,
        count: processes.length,
        filters: {
          category: input.category,
          persona: input.persona,
          tags: input.tags,
          isActive: input.isActive
        }
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to list processes: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * List executions
 */
const listExecutionsTool = createTool<ListExecutionsInput, any>({
  name: 'list_executions',
  description: 'List process executions',
  category: 'process-automation',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      processId: {
        type: 'string',
        description: 'Filter by process ID',
        pattern: '^[a-zA-Z0-9-]+$'
      },
      status: {
        type: 'string',
        enum: ['pending', 'running', 'completed', 'failed', 'cancelled'],
        description: 'Filter by status'
      },
      limit: {
        type: 'integer',
        description: 'Maximum number of results',
        minimum: 1,
        maximum: 100,
        default: 20
      },
      offset: {
        type: 'integer',
        description: 'Offset for pagination',
        minimum: 0,
        default: 0
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: ListExecutionsInput, context: RequestContext) {
    try {
      let query = `
        SELECT e.*, p.name as process_name 
        FROM process_executions e
        JOIN process_definitions p ON e.process_id = p.id
        WHERE e.project_id = ?
      `;
      const params: any[] = [context.projectId || 'default'];

      if (input.processId) {
        query += ' AND e.process_id = ?';
        params.push(input.processId);
      }

      if (input.status) {
        query += ' AND e.status = ?';
        params.push(input.status);
      }

      query += ' ORDER BY e.started_at DESC LIMIT ? OFFSET ?';
      params.push(input.limit || 20, input.offset || 0);

      const result = await context.db.query(query, params);

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to list executions',
          category: 'system'
        });
      }

      const executions = (result.data || []).map((exec: any) => ({
        id: exec.id,
        processId: exec.process_id,
        processName: exec.process_name,
        processVersion: exec.process_version,
        status: exec.status,
        triggeredBy: exec.triggered_by,
        triggerType: exec.trigger_type,
        variables: JSON.parse(exec.variables || '{}'),
        errorMessage: exec.error_message,
        errorCode: exec.error_code,
        startedAt: new Date(exec.started_at).toISOString(),
        completedAt: exec.completed_at ? new Date(exec.completed_at).toISOString() : null,
        duration: exec.duration
      }));

      return createSuccessResult({
        executions,
        count: executions.length,
        limit: input.limit || 20,
        offset: input.offset || 0
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to list executions: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Suggest triggers for a process
 */
const suggestTriggersTool = createTool<SuggestTriggersInput, any>({
  name: 'suggest_triggers',
  description: 'Get AI-powered trigger suggestions for a process',
  category: 'process-automation',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      processName: {
        type: 'string',
        description: 'Process name'
      },
      activities: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            type: { type: 'string' },
            name: { type: 'string' },
            toolName: { type: 'string' }
          },
          required: ['type', 'name']
        },
        description: 'Process activities'
      },
      persona: {
        type: 'string',
        description: 'Persona type'
      }
    },
    required: ['processName', 'activities'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: SuggestTriggersInput, context: RequestContext) {
    try {
      // This is a simplified version - in production, this would use AI
      const suggestions = [];

      // Analyze activities to suggest appropriate triggers
      const hasDevActivities = input.activities.some(a => 
        a.toolName?.includes('test') || a.toolName?.includes('build') || a.toolName?.includes('deploy')
      );

      const hasDataActivities = input.activities.some(a => 
        a.toolName?.includes('backup') || a.toolName?.includes('sync') || a.toolName?.includes('report')
      );

      const hasReviewActivities = input.activities.some(a => 
        a.type === 'human' || a.toolName?.includes('review') || a.toolName?.includes('approve')
      );

      // Development-related triggers
      if (hasDevActivities) {
        suggestions.push({
          type: 'event',
          name: 'On Code Push',
          config: {
            eventType: 'git.push',
            branch: 'main'
          },
          reasoning: 'Automatically run tests and builds when code is pushed',
          confidence: 0.9
        });

        suggestions.push({
          type: 'schedule',
          name: 'Nightly Build',
          config: {
            cronExpression: '0 2 * * *',
            timezone: 'UTC'
          },
          reasoning: 'Run comprehensive tests during off-hours',
          confidence: 0.8
        });
      }

      // Data-related triggers
      if (hasDataActivities) {
        suggestions.push({
          type: 'schedule',
          name: 'Daily Backup',
          config: {
            cronExpression: '0 3 * * *',
            timezone: 'UTC'
          },
          reasoning: 'Regular backups ensure data safety',
          confidence: 0.95
        });

        suggestions.push({
          type: 'condition',
          name: 'On Storage Threshold',
          config: {
            condition: 'storage.usage > 80',
            checkInterval: 3600
          },
          reasoning: 'Trigger cleanup or alerts when storage is high',
          confidence: 0.85
        });
      }

      // Review-related triggers
      if (hasReviewActivities) {
        suggestions.push({
          type: 'webhook',
          name: 'External Request',
          config: {
            path: `/webhooks/process/${input.processName.toLowerCase().replace(/\s+/g, '-')}`,
            auth: 'bearer'
          },
          reasoning: 'Allow external systems to trigger reviews',
          confidence: 0.7
        });
      }

      // Always suggest manual trigger
      suggestions.push({
        type: 'manual',
        name: 'Manual Execution',
        config: {},
        reasoning: 'Always useful for testing and ad-hoc runs',
        confidence: 1.0
      });

      return createSuccessResult({
        suggestions: suggestions.sort((a, b) => b.confidence - a.confidence),
        processContext: {
          name: input.processName,
          activityCount: input.activities.length,
          persona: input.persona
        }
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to suggest triggers: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * List process templates
 */
const listTemplatesTool = createTool<{}, any>({
  name: 'process_list_templates',
  description: 'List available process templates',
  category: 'process-automation',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {},
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: {}, context: RequestContext) {
    try {
      const result = await context.db.query(
        'SELECT * FROM process_templates WHERE project_id = ? OR is_system = TRUE ORDER BY category, name',
        [context.projectId || 'default']
      );

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to list templates',
          category: 'system'
        });
      }

      const templates = (result.data || []).map((template: any) => ({
        id: template.id,
        name: template.name,
        description: template.description,
        category: template.category,
        persona: template.persona,
        isSystem: template.is_system,
        variables: JSON.parse(template.variables || '{}'),
        createdAt: new Date(template.created_at).toISOString()
      }));

      // Group by category
      const templatesByCategory = templates.reduce((acc: any, template: any) => {
        if (!acc[template.category]) {
          acc[template.category] = [];
        }
        acc[template.category].push(template);
        return acc;
      }, {});

      return createSuccessResult({
        templates,
        templatesByCategory,
        count: templates.length
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to list templates: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Create process from template
 */
const createFromTemplateTool = createTool<CreateFromTemplateInput, any>({
  name: 'process_create_from_template',
  description: 'Create a process from a template',
  category: 'process-automation',
  inputSchema: {
    type: 'object',
    properties: {
      templateId: {
        type: 'string',
        description: 'Template ID',
        pattern: '^[a-zA-Z0-9-]+$'
      },
      name: {
        type: 'string',
        description: 'Process name',
        minLength: 1,
        maxLength: 200
      },
      description: {
        type: 'string',
        description: 'Process description',
        maxLength: 1000
      },
      variables: {
        type: 'object',
        description: 'Override template variables'
      }
    },
    required: ['templateId', 'name'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: CreateFromTemplateInput, context: RequestContext) {
    try {
      // Get template
      const templateResult = await context.db.get(
        'SELECT * FROM process_templates WHERE id = ? AND (project_id = ? OR is_system = TRUE)',
        [input.templateId, context.projectId || 'default']
      );

      if (!templateResult.success || !templateResult.data) {
        return createErrorResult({
          code: 'RESOURCE_NOT_FOUND',
          message: 'Template not found',
          category: 'validation'
        });
      }

      const template = templateResult.data;
      const processDefinition = JSON.parse(template.process_definition);
      const templateVariables = JSON.parse(template.variables || '{}');

      // Merge variables
      const finalVariables = { ...templateVariables, ...input.variables };

      // Create process from template
      const createInput: CreateProcessInput = {
        name: input.name,
        description: input.description || template.description,
        version: '1.0.0',
        persona: template.persona,
        category: template.category,
        tags: processDefinition.tags || [],
        triggers: processDefinition.triggers || [{
          type: 'manual',
          name: 'Manual Trigger',
          enabled: true,
          config: {}
        }],
        activities: processDefinition.activities,
        variables: finalVariables,
        onSuccess: processDefinition.onSuccess,
        onFailure: processDefinition.onFailure
      };

      // Use the create process tool
      return await createProcessTool.execute(createInput, context);

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to create from template: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Setup process automation tools
 */
export async function setupProcessAutomationTools(): Promise<ToolRegistration> {
  return {
    module: 'process-automation',
    tools: [
      createProcessTool,
      executeProcessTool,
      listProcessesTool,
      listExecutionsTool,
      suggestTriggersTool,
      listTemplatesTool,
      createFromTemplateTool
    ]
  };
}