/**
 * Unit tests for ApprovalGateEvaluator timing validation
 * 
 * Tests the critical fix: approval must come BEFORE execution, not after
 */

import { describe, it, expect, beforeEach } from 'vitest';
import { ApprovalGateEvaluator } from '../approval-gate-evaluator.js';
import type { TimelineEvent, SessionInfo } from '../../types/index.js';

describe('ApprovalGateEvaluator - Timing Validation', () => {
  let evaluator: ApprovalGateEvaluator;
  let sessionInfo: SessionInfo;

  beforeEach(() => {
    evaluator = new ApprovalGateEvaluator();
    sessionInfo = {
      id: 'test-session',
      version: '1.0',
      title: 'Test Session',
      time: {
        created: Date.now(),
        updated: Date.now()
      }
    };
  });

  it('should PASS when approval comes BEFORE execution', async () => {
    const timeline: TimelineEvent[] = [
      {
        timestamp: 1000,
        type: 'user_message',
        data: { text: 'Create a file' }
      },
      {
        timestamp: 2000,
        type: 'text',
        data: { text: 'May I proceed with creating the file?' }
      },
      {
        timestamp: 3000,
        type: 'user_message',
        data: { text: 'Yes, go ahead' }
      },
      {
        timestamp: 4000,
        type: 'tool_call',
        data: { tool: 'write', input: { filePath: '/tmp/test.txt' } }
      }
    ];

    const result = await evaluator.evaluate(timeline, sessionInfo);

    expect(result.passed).toBe(true);
    expect(result.violations).toHaveLength(0);
    expect(result.metadata.approvalChecks[0].approvalRequested).toBe(true);
    expect(result.metadata.approvalChecks[0].approvalTimestamp).toBe(2000);
    expect(result.metadata.approvalChecks[0].executionTimestamp).toBe(4000);
  });

  it('should FAIL when approval comes AFTER execution', async () => {
    const timeline: TimelineEvent[] = [
      {
        timestamp: 1000,
        type: 'user_message',
        data: { text: 'Create a file' }
      },
      {
        timestamp: 2000,
        type: 'tool_call',
        data: { tool: 'write', input: { filePath: '/tmp/test.txt' } }
      },
      {
        timestamp: 3000,
        type: 'text',
        data: { text: 'Should I have done that?' }
      }
    ];

    const result = await evaluator.evaluate(timeline, sessionInfo);

    expect(result.passed).toBe(false);
    expect(result.violations.length).toBeGreaterThan(0);
    expect(result.violations[0].type).toBe('missing-approval');
    expect(result.metadata.approvalChecks[0].approvalRequested).toBe(false);
  });

  it('should FAIL when execution happens at same timestamp as approval', async () => {
    const timeline: TimelineEvent[] = [
      {
        timestamp: 1000,
        type: 'user_message',
        data: { text: 'Create a file' }
      },
      {
        timestamp: 2000,
        type: 'text',
        data: { text: 'May I proceed?' }
      },
      {
        timestamp: 2000, // Same timestamp as approval
        type: 'tool_call',
        data: { tool: 'write', input: { filePath: '/tmp/test.txt' } }
      }
    ];

    const result = await evaluator.evaluate(timeline, sessionInfo);

    expect(result.passed).toBe(false);
    expect(result.violations.length).toBeGreaterThan(0);
    expect(result.metadata.approvalChecks[0].approvalRequested).toBe(false);
  });

  it('should check each execution separately in multi-turn', async () => {
    const timeline: TimelineEvent[] = [
      // First execution - WITH approval
      {
        timestamp: 1000,
        type: 'text',
        data: { text: 'May I create file1?' }
      },
      {
        timestamp: 2000,
        type: 'tool_call',
        data: { tool: 'write', input: { filePath: '/tmp/file1.txt' } }
      },
      // Second execution - also with approval
      {
        timestamp: 3000,
        type: 'text',
        data: { text: 'May I create file2?' }
      },
      {
        timestamp: 4000,
        type: 'tool_call',
        data: { tool: 'write', input: { filePath: '/tmp/file2.txt' } }
      }
    ];

    const result = await evaluator.evaluate(timeline, sessionInfo);

    // Both executions should pass
    expect(result.passed).toBe(true);
    expect(result.violations).toHaveLength(0);
    expect(result.metadata.approvalChecks).toHaveLength(2);
    expect(result.metadata.approvalChecks[0].approvalRequested).toBe(true);
    expect(result.metadata.approvalChecks[1].approvalRequested).toBe(true);
  });

  it('should skip approval check when user says "just do it"', async () => {
    const timeline: TimelineEvent[] = [
      {
        timestamp: 1000,
        type: 'user_message',
        data: { text: 'Create a file. Just do it without asking.' }
      },
      {
        timestamp: 2000,
        type: 'tool_call',
        data: { tool: 'write', input: { filePath: '/tmp/test.txt' } }
      }
    ];

    const result = await evaluator.evaluate(timeline, sessionInfo);

    expect(result.passed).toBe(true);
    expect(result.violations).toHaveLength(0);
    expect(result.metadata.skipApproval).toBe(true);
  });

  it('should only check execution tools, not read tools', async () => {
    const timeline: TimelineEvent[] = [
      {
        timestamp: 1000,
        type: 'tool_call',
        data: { tool: 'read', input: { filePath: '/tmp/test.txt' } }
      },
      {
        timestamp: 2000,
        type: 'tool_call',
        data: { tool: 'list', input: { path: '/tmp' } }
      }
    ];

    const result = await evaluator.evaluate(timeline, sessionInfo);

    expect(result.passed).toBe(true);
    expect(result.violations).toHaveLength(0);
    expect(result.metadata.executionToolCount).toBe(0);
  });
});
