/**
 * Execute Live Node
 * 
 * Purpose: Execute test in live browser using MCP Playwright tools
 * 
 * Configuration:
 * - capabilities: Declares ['browser'] — framework injects the appropriate MCP server
 * - outputSchema: Structured JSON with execution results, actions, assertions
 * - Model: Configured in .zibby.config.mjs → agent.claude.model or agent.cursor.model
 */

import { z, SKILLS } from '@zibby/core';
import { formatAssertionChecklist } from './utils.mjs';

export const executeLiveNode = {
  name: 'execute_live',
  skills: [SKILLS.BROWSER, SKILLS.MEMORY],
  timeout: 600000,

  prompt: (state) => {
    const ctx = state.context;
    const contextInfo = ctx ? `
Domain Knowledge & Environment:
${ctx.global || ''}
${ctx.pathBased ? `Test-Specific Info:\n${ctx.pathBased}\n` : ''}
${ctx.env ? `Environment Config:\n${JSON.stringify(ctx.env, null, 2)}\n` : ''}
---
` : '';

    const assertionChecklist = formatAssertionChecklist(state.preflight?.assertions);
    
    return `⚠️  CRITICAL: At the END, output ONLY the JSON object. NO explanations after the JSON.

🎯 YOUR GOAL: Execute the test steps and collect evidence for script generation.
   You don't need perfect verification - just capture the key actions and results.
   The next node will generate the actual test script from your execution.

${contextInfo}
${state.testSpec}
${assertionChecklist ? `
═══════════════════════════════════════════════════
🎯 ASSERTION CHECKLIST (MANDATORY - from test spec)
You MUST include ALL of these in your 'assertions' array.
Report each as passed: true or passed: false with evidence.
DO NOT skip any. DO NOT add extras.

${assertionChecklist}
═══════════════════════════════════════════════════
` : ''}
⚠️  CRITICAL RULES (STRICT ENFORCEMENT):
1. DO NOT get stuck in read loops - if a snapshot is large, move on
2. DO NOT over-analyze - just execute the steps
3. **As soon as you complete the test → IMMEDIATELY return JSON**
4. **NO screenshots required** - just execute and return JSON
5. **If test is done, STOP - don't try to be perfect**
6. **USE VALUES FROM THE TEST SPEC** - if the spec provides specific values, use them exactly. Do NOT replace them with random data.
7. **USE UNIQUE DATA ONLY when CREATING new resources** (e.g., sign-up forms, new accounts) to avoid "already taken" conflicts:
   - For NEW emails (not provided in test spec): use random digits like "test84729@example.com"
   - For NEW names (not provided in test spec): append random digits like "John84729"
   - This does NOT apply to login credentials or test data explicitly provided in the spec

WHEN TO STOP (MANDATORY):
✓ You've completed the test steps
✓ Test outcome is visible (even briefly)
→ **RETURN JSON IMMEDIATELY - DO NOT make any more tool calls**

DO NOT:
- Navigate to the same URL multiple times
- Use browser_run_code or browser_evaluate
- Read large snapshots repeatedly (max 2 snapshots per page)
- Take screenshots (optional, skip if slowing you down)
- Try to verify every single detail - focus on the MAIN outcome
- Click/scroll/interact after seeing the expected result
- Spend more than 2 minutes on any single page
- Try to click elements that aren't immediately visible

EXECUTION SEQUENCE (MANDATORY - FOLLOW STRICTLY):
1. Execute the test steps efficiently (navigate, fill, click)
   - Max 10-15 actions total
   - If stuck, move on to next step
2. Quick verification - check if main result is visible
   - **If you see expected result → IMMEDIATELY return JSON**
   - Don't try to make it perfect - good enough is enough
3. **RETURN JSON AND STOP COMPLETELY**
   - Format: { "success": true, "steps": ["step 1", ...], "browserClosed": true, "actions": [...] }
   - MUST include: "success" (boolean), "steps" (array), "browserClosed" (boolean)
   - Keep JSON CONCISE - short descriptions, no excessive detail
   - After the closing brace }, DO NOT write ANYTHING
   - NO commentary, NO explanations, NO additional text
   - NO second JSON object
   - Just the JSON, then STOP

IMPORTANT for 'actions' array (STRICT 1:1 MAPPING):
- Each entry MUST match EXACTLY ONE browser tool call.
- DO NOT group multiple tool calls into one action.
- DO NOT combine multiple 'fill' calls into one action.
- If you call browser_type 3 times for 3 fields, you MUST have 3 actions in the array.
- Include actual values/URLs in descriptions.
- Keep descriptions SHORT (5-10 words max).

IMPORTANT for 'assertions' array (USE THE CHECKLIST ABOVE):
- Your assertions array MUST match the ASSERTION CHECKLIST exactly - one entry per item
- If you verified it and it passed → "passed": true
- If you could NOT verify it or it wasn't found → "passed": false with evidence of what you saw instead
- Each assertion MUST include 'verifiedAfterAction' (0-based action index after which you checked)
- Format: {"description": "...", "passed": true/false, "verifiedAfterAction": N, "evidence": "..."}

🔍 CRITICAL: CAPTURE ROBUST SELECTORS (for script generation)
For EACH action, capture multiple selector strategies in priority order:

1. **Role + Name** (Most Robust - Accessibility-first):
   - Role: button/textbox/link/etc
   - Name: visible text or aria-label
   Example: {"role": "button", "name": "Login"}

2. **Stable Attributes** (Good Stability):
   - name, type, placeholder, aria-label
   Example: {"attributes": {"name": "username", "type": "text", "placeholder": "Enter username"}}

3. **Partial Match** (For Dynamic Elements):
   - Use starts-with for dynamic IDs/classes
   Example: {"partialMatch": {"id": "^user-", "class": "^btn-"}}

4. **Structural** (Fallback):
   - Tag + position relative to stable landmark
   Example: {"structure": "form input[type='text']:nth-of-type(1)"}

Format for actions with selectors:
{
  "description": "Fill username field with 'joe'",
  "reasoning": "Need to authenticate user",
  "type": "fill",
  "selectors": {
    "role": {"role": "textbox", "name": "Username"},
    "attributes": {"name": "username", "type": "text", "placeholder": "请输入账号"},
    "structure": "form input[type='text']:first-of-type"
  },
  "value": "joe"
}

IMPORTANT for 'evidenceScreenshots' (array) - OPTIONAL:
- Screenshots are OPTIONAL - only take if helpful
- If you take screenshots, use descriptive filenames
- Filename pattern: "{step-number}-{action-or-state}.png"
- Keep it minimal - test execution is more important than documentation
`;
  },
  
  outputSchema: z.object({
    success: z.boolean()
      .describe('Whether the test execution completed successfully'),
    
    steps: z.array(z.string())
      .describe('Array of test steps executed'),
    
    finalUrl: z.string()
      .nullish()
      .describe('Final URL after test execution'),
    
    actions: z.array(z.object({
      type: z.string()
        .describe('Action type: navigate, click, fill, type, select, keypress, hover, drag'),
      description: z.string()
        .describe('Human-readable description of the action'),
      reasoning: z.string().nullish()
        .describe('Why this action was performed'),
      selectors: z.object({
        role: z.object({
          role: z.string().describe('ARIA role (e.g. button, link, textbox, generic)'),
          name: z.string().nullish().describe('Accessible name of the element')
        }).nullish().describe('Role-based selector for fallback matching')
      }).nullish()
        .describe('Element selectors captured during the action'),
      value: z.string().nullish()
        .describe('Value entered for fill/type actions')
    }))
      .nullish()
      .describe('Detailed array of actions performed with descriptions and reasoning'),
    
    assertions: z.array(z.object({
      description: z.string()
        .describe('What was verified'),
      passed: z.boolean()
        .describe('Whether the assertion passed'),
      verifiedAfterAction: z.number()
        .describe('Index of the action after which this was verified (0-based, matches actions array index) - REQUIRED'),
      evidence: z.string()
        .nullish()
        .describe('Brief evidence of what was observed')
    }))
      .nullish()
      .describe('Array of assertions made during test'),
    
    waits: z.array(z.object({
      description: z.string().describe('What the wait is for'),
      duration: z.number().nullish().describe('Wait duration in milliseconds'),
      condition: z.string().nullish().describe('Wait condition expression')
    }))
      .nullish()
      .describe('Array of waits needed for proper test execution'),
    
    evidenceScreenshots: z.array(z.object({
      filename: z.string()
        .describe('Descriptive filename pattern: {step-number}-{action-or-state}.png'),
      
      description: z.string()
        .describe('What the screenshot shows and why it is evidence'),
      
      verdict: z.enum(['pass', 'fail', 'info'])
        .describe('Test verdict: pass/fail for validation points, info for checkpoints')
    }))
      .nullish()
      .describe('Array of screenshots taken at key validation points throughout the test'),
    
    browserClosed: z.boolean()
      .describe('Whether the browser was properly closed (should always be true)'),
    
    notes: z.string()
      .nullish()
      .describe('Additional notes or observations. REQUIRED when success=false to explain why test failed or could not execute')
  })
};
