import { describe, it, expect } from 'vitest';
import { parseToolPolicy, resolveWorkspaceTools } from './workspace-tool-policy.js';

describe('workspace tool policy', () => {
  it('parse failure / null → empty policy (fail-closed)', () => {
    expect(parseToolPolicy(null)).toEqual({});
    expect(parseToolPolicy('not json')).toEqual({});
  });
  it('default policy: safe tools on, sensitive off', async () => {
    const r = await resolveWorkspaceTools({});
    expect(r.allowedTools).toContain('Read');
    expect(r.allowedTools).toContain('WebSearch');
    expect(r.allowedTools).toContain('ReadToolDoc');   // META always
    expect(r.allowedTools).not.toContain('Bash');       // sensitive tool
    expect(r.allowedTools).not.toContain('SpawnSubTask'); // D1: sensitive (opt-in) tool
    expect(r.allowedTools).toContain('delegate');        // D1: serial decomposition is default-on
    expect(r.allowedTools).toContain('WaitSubTask');     // default-on (no-op without children)
    expect(r.allowedTools).not.toContain('BrowseWeb');  // sensitive category
    expect(r.allowedTools).not.toContain('SshExec');
    expect(r.editAllowed).toBe(true);                   // Write/Edit are safe-on
  });
  it('enabledSensitive turns on Bash / browser only when listed', async () => {
    const r = await resolveWorkspaceTools({ enabledSensitive: ['Bash', 'browser'] });
    expect(r.allowedTools).toContain('Bash');
    expect(r.allowedTools).toContain('BrowseWeb');
    expect(r.allowedTools).not.toContain('SshExec');    // ssh not opted in
  });
  it('enabledSensitive turns on SpawnSubTask only when listed (D1)', async () => {
    expect((await resolveWorkspaceTools({})).allowedTools).not.toContain('SpawnSubTask');
    const r = await resolveWorkspaceTools({ enabledSensitive: ['SpawnSubTask'] });
    expect(r.allowedTools).toContain('SpawnSubTask');
    expect(r.allowedTools).toContain('delegate');        // delegate stays available
    expect(r.allowedTools).toContain('WaitSubTask');     // pairs cleanly when opted in
  });
  it('disabledSafe removes a safe category', async () => {
    const r = await resolveWorkspaceTools({ disabledSafe: ['web'] });
    expect(r.allowedTools).not.toContain('WebSearch');
    expect(r.allowedTools).toContain('Read');
  });

  // MCP is governed by per-space server connection (opt-in by connecting), not by
  // this builtin policy. The effective set must carry the `mcp__*` pass-through so
  // the MCP aggregator (which returns [] when no mcp__ pattern is present, and is
  // itself space + token scoped) surfaces the workspace's connected MCP tools.
  it('always includes the mcp__* pass-through so connected MCP tools surface', async () => {
    expect((await resolveWorkspaceTools({})).allowedTools).toContain('mcp__*');
    expect((await resolveWorkspaceTools({ disabledSafe: ['web'] })).allowedTools).toContain('mcp__*');
    expect((await resolveWorkspaceTools({ enabledSensitive: ['Bash'] })).allowedTools).toContain('mcp__*');
  });
});
