/**
 * VL AutoTest - Test Evaluator
 * Uses Claude API to evaluate test results by comparing snapshots with expectations
 */

export const EVAL_SYSTEM = `You are an automated test result evaluation expert. Your task is to determine whether a test passed based on the test case's expected result and actual browser snapshots.

For each test case result, you need to analyze:
1. Whether the actual browser DOM snapshot matches expectations
2. Error messages from step execution
3. UI state visible in screenshots

Output format (JSON):
{
  "pass": true/false,
  "confidence": 0.0-1.0,
  "reason": "Judgment rationale",
  "evidence": "Key evidence extracted from snapshots",
  "suggestions": ["Improvement suggestion 1", "Improvement suggestion 2"]
}

Judgment criteria:
- All steps executed successfully -> pass
- Final page state matches expectedResult description -> pass
- Any step failed but final state still matches expectations -> requires careful evaluation
- Final state clearly does not match expectations -> fail
- When in doubt, lean toward fail and explain in reason

Output strict JSON only, no other content.`;

export class TestEvaluator {
  constructor(anthropicClient) {
    this.client = anthropicClient;
    this.model = 'claude-sonnet-4-6';
  }

  /**
   * Evaluate a single test case result
   */
  async evaluateCase(testCase, runResult, onProgress) {
    onProgress?.({
      phase: 'eval',
      caseId: testCase.id,
      status: 'running',
      message: `Evaluating case ${testCase.id}: ${testCase.name}`,
    });

    // If all steps passed with no errors, it's a pass
    if (runResult.pass && runResult.steps.every(s => s.status === 'passed')) {
      const evalResult = {
        pass: true,
        confidence: 0.95,
        reason: 'All test steps executed successfully',
        evidence: `All ${runResult.steps.length} steps passed`,
        suggestions: [],
      };

      onProgress?.({
        phase: 'eval',
        caseId: testCase.id,
        status: 'done',
        message: `Case ${testCase.id} evaluation complete: PASS`,
        data: evalResult,
      });

      return evalResult;
    }

    // For failures or ambiguous results, use LLM to evaluate
    const snapshotInfo = runResult.snapshots?.length > 0
      ? runResult.snapshots.map(s => `[${s.type} at step ${s.stepIndex}]:\n${s.snapshot}`).join('\n\n')
      : '[no snapshot data]';

    const stepsInfo = runResult.steps.map((s, i) =>
      `Step ${i + 1}: ${s.action} - ${s.status}${s.error ? ` (Error: ${s.error})` : ''}`
    ).join('\n');

    const userMessage = `Test case: ${testCase.name} (${testCase.id})
Expected result: ${testCase.expectedResult}
Test page: ${testCase.page}

Step execution results:
${stepsInfo}

${runResult.error ? `Execution error: ${runResult.error}` : ''}

Browser snapshots:
${snapshotInfo}`;

    try {
      const response = await this.client.messages.create({
        model: this.model,
        max_tokens: 2048,
        system: EVAL_SYSTEM,
        messages: [{ role: 'user', content: userMessage }],
      });

      const text = response.content[0].text;
      const evalResult = this._parseJSON(text);

      onProgress?.({
        phase: 'eval',
        caseId: testCase.id,
        status: 'done',
        message: `Case ${testCase.id} evaluation complete: ${evalResult.pass ? 'PASS' : 'FAIL'}`,
        data: evalResult,
      });

      return evalResult;
    } catch (err) {
      // Fallback: use step results directly
      const evalResult = {
        pass: runResult.pass,
        confidence: 0.5,
        reason: `LLM evaluation failed (${err.message}), using step execution results as judgment basis`,
        evidence: runResult.error || 'none',
        suggestions: ['Recommend retrying evaluation'],
      };

      onProgress?.({
        phase: 'eval',
        caseId: testCase.id,
        status: 'done',
        message: `Case ${testCase.id} evaluation complete (degraded): ${evalResult.pass ? 'PASS' : 'FAIL'}`,
        data: evalResult,
      });

      return evalResult;
    }
  }

  /**
   * Evaluate all test results in batch
   */
  async evaluateAll(testCases, runResults, onProgress) {
    const evaluations = [];

    for (let i = 0; i < testCases.length; i++) {
      const tc = testCases[i];
      const result = runResults.find(r => r.caseId === tc.id);
      if (!result) continue;

      const evaluation = await this.evaluateCase(tc, result, onProgress);
      evaluations.push({
        caseId: tc.id,
        name: tc.name,
        runResult: result,
        evaluation,
      });
    }

    return evaluations;
  }

  _parseJSON(text) {
    try {
      return JSON.parse(text);
    } catch (e) {
      const match = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
      if (match) return JSON.parse(match[1]);
      const jsonMatch = text.match(/(\{[\s\S]*\})/);
      if (jsonMatch) return JSON.parse(jsonMatch[1]);
      throw new Error('Failed to parse evaluation result JSON');
    }
  }
}
