import { describe, it, expect, vi } from 'vitest';
import { HookEngine } from './engine.js';

describe('HookEngine', () => {
  it('returns silent action for non-matching tools', async () => {
    const engine = new HookEngine({
      confirm: ['shell.*'],
      log: ['web.*'],
      silent: [],
    });

    const action = engine.getAction('unknown.tool');
    expect(action).toBe('silent');
  });

  it('returns confirm action for matching confirm patterns', () => {
    const engine = new HookEngine({
      confirm: ['shell.*', 'file.write'],
      log: [],
      silent: [],
    });

    expect(engine.getAction('shell.exec')).toBe('confirm');
    expect(engine.getAction('shell.run')).toBe('confirm');
    expect(engine.getAction('file.write')).toBe('confirm');
    expect(engine.getAction('file.read')).toBe('silent');
  });

  it('returns log action for matching log patterns', () => {
    const engine = new HookEngine({
      confirm: [],
      log: ['web.*'],
      silent: [],
    });

    expect(engine.getAction('web.fetch')).toBe('log');
    expect(engine.getAction('web.search')).toBe('log');
  });

  it('queues confirmation and resolves when approved', async () => {
    const engine = new HookEngine({
      confirm: ['shell.*'],
      log: [],
      silent: [],
    });

    const confirmPromise = engine.requestConfirmation('shell.exec', { cmd: 'ls' });

    const pending = engine.getPendingConfirmations();
    expect(pending).toHaveLength(1);
    expect(pending[0].tool).toBe('shell.exec');

    engine.resolveConfirmation(pending[0].id, { approved: true });

    const result = await confirmPromise;
    expect(result.approved).toBe(true);
  });

  it('resolves with denied when rejected', async () => {
    const engine = new HookEngine({
      confirm: ['shell.*'],
      log: [],
      silent: [],
    });

    const confirmPromise = engine.requestConfirmation('shell.exec', { cmd: 'rm -rf' });

    const pending = engine.getPendingConfirmations();
    engine.resolveConfirmation(pending[0].id, { approved: false, reason: 'Too dangerous' });

    const result = await confirmPromise;
    expect(result.approved).toBe(false);
    expect(result.reason).toBe('Too dangerous');
  });

  it('uses interactive confirmer when set (no pending queue)', async () => {
    const engine = new HookEngine({ confirm: ['shell.*'], log: [], silent: [] });
    const confirmer = vi.fn(async () => ({ approved: true }));
    engine.setInteractiveConfirmer(confirmer);

    const result = await engine.requestConfirmation('shell.exec', { cmd: 'ls' });
    expect(result.approved).toBe(true);
    expect(engine.getPendingConfirmations()).toHaveLength(0);
    expect(confirmer).toHaveBeenCalledOnce();
    expect(confirmer).toHaveBeenCalledWith(expect.objectContaining({
      tool: 'shell.exec',
      args: { cmd: 'ls' },
    }));
  });
});
