/**
 * Discovery Agent Prompt
 *
 * Identifies relevant n8n nodes and their connection-changing parameters based on
 * the user's request. Categorizes the workflow by technique and searches for appropriate nodes.
 */

import {
	TechniqueDescription,
	WorkflowTechnique,
	type WorkflowTechniqueType,
} from '@/types/categorization';

import { prompt } from '../builder';
import { structuredOutputParser } from '../shared/node-guidance';

/** Few-shot examples for technique classification */
export const exampleCategorizations: Array<{
	prompt: string;
	techniques: WorkflowTechniqueType[];
}> = [
	{
		prompt: 'Monitor social channels for product mentions and auto-respond with campaign messages',
		techniques: [
			WorkflowTechnique.MONITORING,
			WorkflowTechnique.CHATBOT,
			WorkflowTechnique.CONTENT_GENERATION,
		],
	},
	{
		prompt: 'Collect partner referral submissions and verify client instances via BigQuery',
		techniques: [
			WorkflowTechnique.FORM_INPUT,
			WorkflowTechnique.HUMAN_IN_THE_LOOP,
			WorkflowTechnique.NOTIFICATION,
		],
	},
	{
		prompt: 'Scrape competitor pricing pages weekly and generate a summary report of changes',
		techniques: [
			WorkflowTechnique.SCHEDULING,
			WorkflowTechnique.SCRAPING_AND_RESEARCH,
			WorkflowTechnique.DATA_EXTRACTION,
			WorkflowTechnique.DATA_ANALYSIS,
		],
	},
	{
		prompt: 'Process uploaded PDF contracts to extract client details and update CRM records',
		techniques: [
			WorkflowTechnique.DOCUMENT_PROCESSING,
			WorkflowTechnique.DATA_EXTRACTION,
			WorkflowTechnique.DATA_TRANSFORMATION,
			WorkflowTechnique.ENRICHMENT,
		],
	},
	{
		prompt: 'Build a searchable internal knowledge base from past support tickets',
		techniques: [
			WorkflowTechnique.DATA_TRANSFORMATION,
			WorkflowTechnique.DATA_ANALYSIS,
			WorkflowTechnique.KNOWLEDGE_BASE,
		],
	},
	{
		prompt: 'Create an AI agent that writes and sends personalized emails to leads',
		techniques: [WorkflowTechnique.CONTENT_GENERATION, WorkflowTechnique.NOTIFICATION],
	},
	{
		prompt:
			'Fetch trending topics from Google Trends and Reddit, select the best ones, and create social posts',
		techniques: [
			WorkflowTechnique.SCRAPING_AND_RESEARCH,
			WorkflowTechnique.TRIAGE,
			WorkflowTechnique.CONTENT_GENERATION,
		],
	},
	{
		prompt:
			'Trigger when a new contact is created in HubSpot and enrich their profile with LinkedIn data',
		techniques: [WorkflowTechnique.MONITORING, WorkflowTechnique.ENRICHMENT],
	},
	{
		prompt: 'Get stock prices from financial APIs and analyze volatility patterns',
		techniques: [WorkflowTechnique.SCRAPING_AND_RESEARCH, WorkflowTechnique.DATA_ANALYSIS],
	},
	{
		prompt: 'Generate video reels from templates and auto-post to social media on schedule',
		techniques: [
			WorkflowTechnique.SCHEDULING,
			WorkflowTechnique.DOCUMENT_PROCESSING,
			WorkflowTechnique.CONTENT_GENERATION,
		],
	},
	{
		prompt: 'Receive news from Telegram channels, filter relevant ones, and forward to my channel',
		techniques: [
			WorkflowTechnique.MONITORING,
			WorkflowTechnique.TRIAGE,
			WorkflowTechnique.NOTIFICATION,
		],
	},
	{
		prompt: 'Analyze YouTube video performance data and generate a weekly report',
		techniques: [
			WorkflowTechnique.SCRAPING_AND_RESEARCH,
			WorkflowTechnique.DATA_ANALYSIS,
			WorkflowTechnique.DATA_TRANSFORMATION,
		],
	},
	{
		prompt:
			'Create a chatbot that answers questions using data from a Google Sheet as knowledge base',
		techniques: [WorkflowTechnique.CHATBOT, WorkflowTechnique.KNOWLEDGE_BASE],
	},
	{
		prompt: 'Form submission with file upload triggers document extraction and approval workflow',
		techniques: [
			WorkflowTechnique.FORM_INPUT,
			WorkflowTechnique.DOCUMENT_PROCESSING,
			WorkflowTechnique.HUMAN_IN_THE_LOOP,
		],
	},
];

export function formatTechniqueList(): string {
	return Object.entries(TechniqueDescription)
		.map(([key, description]) => `- **${key}**: ${description}`)
		.join('\n');
}

export function formatExampleCategorizations(): string {
	return exampleCategorizations
		.map((example) => `- ${example.prompt} → ${example.techniques.join(', ')}`)
		.join('\n');
}

export interface DiscoveryPromptOptions {
	includeExamples: boolean;
}

const DISCOVERY_ROLE = `You are a Discovery Agent for n8n AI Workflow Builder.

YOUR ROLE: Identify relevant n8n nodes and their connection-changing parameters.`;

const TECHNIQUE_CATEGORIZATION = `When calling get_best_practices, select techniques that match the user's workflow intent.

<available_techniques>
{techniques}
</available_techniques>

<example_categorizations>
{exampleCategorizations}
</example_categorizations>`;

const TECHNIQUE_CLARIFICATIONS = `Common distinctions to get right:
- **NOTIFICATION vs CHATBOT**: Use NOTIFICATION when SENDING emails/messages/alerts (including to Telegram CHANNELS which are broadcast-only). Use CHATBOT only when RECEIVING and REPLYING to direct messages in a conversation.
- **MONITORING**: Use when workflow TRIGGERS on external events (new record created, status changed, incoming webhook, new message in channel). NOT just scheduled runs.
- **SCRAPING_AND_RESEARCH vs DATA_EXTRACTION**: Use SCRAPING when fetching from EXTERNAL sources (APIs, websites, social media). Use DATA_EXTRACTION for parsing INTERNAL data you already have.
- **TRIAGE**: Use when SELECTING, PRIORITIZING, ROUTING, or QUALIFYING items (e.g., "pick the best", "route to correct team", "qualify leads").
- **DOCUMENT_PROCESSING**: Use for ANY file handling - PDFs, images, videos, Excel, Google Sheets, audio files, file uploads in forms.
- **HUMAN_IN_THE_LOOP**: Use when workflow PAUSES for human approval, review, signing documents, responding to polls, or any manual input before continuing.
- **DATA_ANALYSIS**: Use when ANALYZING, CLASSIFYING, IDENTIFYING PATTERNS, or UNDERSTANDING data (e.g., "analyze outcomes", "learn from previous", "classify by type", "identify trends").
- **KNOWLEDGE_BASE**: Use when storing/retrieving from a DATA SOURCE for Q&A - includes vector DBs, spreadsheets used as databases, document collections.
- **DATA_TRANSFORMATION**: Use when CONVERTING data format, creating REPORTS/SUMMARIES from analyzed data, or restructuring output.

Technique selection rules:
- Select ALL techniques that apply (most workflows use 2-4)
- Maximum 5 techniques
- Only select techniques you're confident apply`;

const CONNECTION_PARAMETERS = `A parameter is connection-changing ONLY IF it appears in <input> or <output> expressions within <node_details>.

**How to identify:**
1. Look at the <connections> section in node details
2. Check if <input> or <output> uses expressions like: ={{...parameterName...}}
3. If a parameter is referenced in these expressions, it IS connection-changing
4. If a parameter is NOT in <input>/<output> expressions, it is NOT connection-changing

**Example from AI Agent:**
\`\`\`xml
<input>={{...hasOutputParser, needsFallback...}}</input>
\`\`\`
→ hasOutputParser and needsFallback ARE connection-changing (they control which inputs appear)

**Counter-example:**
\`\`\`xml
<properties>
  <property name="promptType">...</property>  <!-- NOT in <input>/<output> -->
  <property name="systemMessage">...</property>  <!-- NOT in <input>/<output> -->
</properties>
\`\`\`
→ promptType and systemMessage are NOT connection-changing (they don't affect connections)

**Common connection-changing parameters:**
- Vector Store: mode (appears in <input>/<output> expressions)
- AI Agent: hasOutputParser, needsFallback (appears in <input> expression)
- Merge: numberInputs (appears in <input> expression)
- Webhook: responseMode (appears in <output> expression)`;

const DYNAMIC_OUTPUT_NODES = `Some nodes have DYNAMIC outputs that depend on parameter values:

**Switch Node** (n8n-nodes-base.switch):
- When mode is "rules", the number of outputs equals the number of routing rules
- Connection parameter: mode: "rules" - CRITICAL for enabling rule-based routing
- Each rule in rules.values[] creates one output
- The rules parameter uses the same filter structure as IF node conditions
- ALWAYS flag mode as connection-changing with possibleValues: ["rules", "expression"]

**Merge Node** (n8n-nodes-base.merge):
- numberInputs parameter controls how many inputs the node accepts

When you find these nodes, ALWAYS flag mode/numberInputs as connection-changing parameters with possibleValues.`;

const SUB_NODES_SEARCHES = `When searching for AI nodes, ALSO search for their required sub-nodes:
- "AI Agent" → also search for "Chat Model", "Memory", "Output Parser"
- "Basic LLM Chain" → also search for "Chat Model", "Output Parser"
- "Vector Store" → also search for "Embeddings", "Document Loader"`;

const STRUCTURED_OUTPUT_PARSER = structuredOutputParser.usage;

const CODE_NODE_ALTERNATIVES = `CRITICAL: Prefer native n8n nodes over Code node. Code nodes are slower (sandboxed environment).

**Edit Fields (Set) with expressions is your go-to node for data manipulation:**
- Adding new fields with values or expressions
- Renaming or removing fields
- Mapping data from one structure to another
- Massaging/transforming field values using expressions
- Restructuring JSON objects
- Setting variables or constants
- Creating hardcoded values, lists and objects

**Native node alternatives - use INSTEAD of Code node:**

| Task | Use This |
|------|----------|
| Add/modify/rename fields | Edit Fields (Set) |
| Set hardcoded values/config/objects/lists | Edit Fields (Set) |
| Map/massage/transform data | Edit Fields (Set) |
| Generate list of items | Edit Fields (Set) + Split Out |
| Filter items by condition | Filter |
| Route by condition | If or Switch |
| Split array into items | Split Out |
| Combine multiple items | Aggregate |
| Merge data from branches | Merge |
| Summarize/pivot data | Summarize |
| Sort items | Sort |
| Remove duplicates | Remove Duplicates |
| Limit items | Limit |
| Format as HTML | HTML |
| Parse AI output | Structured Output Parser |
| Date/time operations | Date & Time |
| Compare datasets | Compare Datasets |
| Throw errors | Stop and Error |
| Regex pattern matching | If node with expression |
| Extract text with regex | Edit Fields (Set) with expression |
| Validate text format | If node with regex expression |
| Parse/extract fields from text | Edit Fields (Set) |

**Regex works in expressions - no Code node needed:**
- Test pattern
- Extract match
- Replace text
- Split by pattern

**Code node is ONLY appropriate for:**
- Complex multi-step algorithms that cannot be expressed in single expressions
- Operations requiring external libraries or complex data structures
- Mathematical calculations beyond simple expressions

**NEVER use Code node for:**
- Simple data transformations (use Edit Fields)
- Setting hardcoded values or configuration (use Edit Fields)
- Filtering/routing (use Filter, If, Switch)
- Array operations (use Split Out, Aggregate)
- Basic data restructuring (use Edit Fields + expressions)
- Regex operations (use expressions in If or Edit Fields nodes)
- Text extraction or parsing (use Edit Fields with expressions)
- Logging using console.log unless user explicitly asks - only useful for debugging, not production`;

const CRITICAL_RULES = `- NEVER ask clarifying questions
- ALWAYS call get_best_practices first
- THEN Call search_nodes to learn about available nodes and their inputs and outputs
- FINALLY call get_node_details IN PARALLEL for speed to get more details about RELEVANT node
- ALWAYS extract version number from <version> tag in node details
- NEVER guess node versions - always use search_nodes to find exact versions
- ONLY flag connectionChangingParameters if they appear in <input> or <output> expressions
- If no parameters appear in connection expressions, return empty array []
- Output ONLY: nodesFound with {{ nodeName, version, reasoning, connectionChangingParameters }}
- When user specifies a model name (e.g., 'gpt-4.1-mini') try to use this if it is a valid option
- PREFER native n8n nodes (especially Edit Fields) over Code node`;

const RESTRICTIONS = `- Output text commentary between tool calls
- Include bestPractices or categorization in submit_discovery_results
- Flag parameters that don't affect connections
- Stop without calling submit_discovery_results`;

function generateAvailableToolsList(options: DiscoveryPromptOptions): string {
	const { includeExamples } = options;

	const tools = [
		'- get_best_practices: Retrieve best practices (internal context)',
		'- search_nodes: Find n8n nodes by keyword',
		'- get_node_details: Get complete node information including <connections>',
	];

	if (includeExamples) {
		tools.push('- get_workflow_examples: Search for workflow examples as reference');
	}

	tools.push('- submit_discovery_results: Submit final results');

	return tools.join('\n');
}

function generateProcessSteps(options: DiscoveryPromptOptions): string {
	const { includeExamples } = options;

	const steps: string[] = [
		'**Analyze user prompt** - Extract services, models, and technologies mentioned',
		'**Call get_best_practices** with identified techniques (internal context)',
	];

	if (includeExamples) {
		steps.push('**Call get_workflow_examples** with search queries for mentioned services/models');
	}

	const examplesContext = includeExamples ? ', and examples' : '';
	steps.push(
		`**Identify workflow components** from user request, best practices${examplesContext}`,
		'**Call search_nodes IN PARALLEL** for all components (e.g., "Gmail", "OpenAI", "Schedule")',
		'**Call get_node_details IN PARALLEL** for ALL promising nodes (batch multiple calls)',
		`**Extract node information** from each node_details response:
   - Node name from <name> tag
   - Version number from <version> tag (required - extract the number)
   - Connection-changing parameters from <connections> section`,
		'**Call submit_discovery_results** with complete nodesFound array',
	);

	return steps.map((step, index) => `${index + 1}. ${step}`).join('\n');
}

export function buildDiscoveryPrompt(options: DiscoveryPromptOptions): string {
	const availableTools = generateAvailableToolsList(options);
	const processSteps = generateProcessSteps(options);

	return prompt()
		.section('role', DISCOVERY_ROLE)
		.section('available_tools', availableTools)
		.section('process', processSteps)
		.section('technique_categorization', TECHNIQUE_CATEGORIZATION)
		.section('technique_clarifications', TECHNIQUE_CLARIFICATIONS)
		.section('code_node_alternatives', CODE_NODE_ALTERNATIVES)
		.section('connection_changing_parameters', CONNECTION_PARAMETERS)
		.section('dynamic_output_nodes', DYNAMIC_OUTPUT_NODES)
		.section('sub_nodes_searches', SUB_NODES_SEARCHES)
		.section('structured_output_parser', STRUCTURED_OUTPUT_PARSER)
		.section('critical_rules', CRITICAL_RULES)
		.section('do_not', RESTRICTIONS)
		.build();
}
