import { describe, expect, it } from 'vitest';

import { DEFAULT_RISK_THRESHOLD, evaluateRiskFloor, type ReviewSurface } from './risk-floor.js';

describe('evaluateRiskFloor', () => {
  it('returns a no-review "none" verdict for an empty diff', () => {
    const v = evaluateRiskFloor({ filesChanged: [] });
    expect(v).toEqual({
      needs_review: false,
      score: 0,
      surface: 'none',
      reason: 'no files changed',
    });
  });

  it('ignores empty/non-string entries', () => {
    const v = evaluateRiskFloor({ filesChanged: ['', '   ' as unknown as string].filter(Boolean) });
    // only the whitespace string survives the Boolean filter; it classifies to none
    expect(v.surface).toBe('none');
    expect(v.needs_review).toBe(false);
  });

  it.each<[string, string, ReviewSurface, boolean]>([
    ['auth', 'apps/api/src/auth/session.guard.ts', 'auth', true],
    ['data', 'packages/db/migrations/0007_add_users.sql', 'data', true],
    ['infra', '.woodpecker/deploy.yml', 'infra', true],
    ['build', 'packages/types/tsconfig.json', 'build', true],
    ['ui', 'apps/web/src/components/Button.tsx', 'ui', false],
    ['test', 'packages/macp/src/risk-floor.spec.ts', 'test', false],
    ['docs', 'docs/plans/agent-reflection-loop-PRD.md', 'docs', false],
    ['none', 'README', 'none', false],
  ])(
    'classifies a single %s file → surface=%s needs_review=%s',
    (_label, file, surface, needsReview) => {
      const v = evaluateRiskFloor({ filesChanged: [file] });
      expect(v.surface).toBe(surface);
      expect(v.needs_review).toBe(needsReview);
      expect(v.reason).toContain(
        file === 'README' ? 'no sensitive surface' : surface === 'none' ? '' : surface,
      );
    },
  );

  it('lets the highest-risk surface dominate a mixed diff', () => {
    const v = evaluateRiskFloor({
      filesChanged: [
        'docs/readme.md',
        'apps/web/src/components/Nav.tsx',
        'apps/api/src/auth/token.service.ts',
      ],
    });
    expect(v.surface).toBe('auth');
    expect(v.score).toBe(1.0);
    expect(v.needs_review).toBe(true);
    expect(v.reason).toContain('token.service.ts');
    expect(v.reason).not.toContain('readme.md');
  });

  it('names every file that ties at the dominant surface', () => {
    const v = evaluateRiskFloor({
      filesChanged: ['src/login.ts', 'src/permission-check.ts'],
    });
    expect(v.surface).toBe('auth');
    expect(v.reason).toContain('src/login.ts');
    expect(v.reason).toContain('src/permission-check.ts');
  });

  it('treats docs+test-only diffs as below the floor', () => {
    const v = evaluateRiskFloor({
      filesChanged: ['docs/guide.md', 'packages/x/src/x.test.ts'],
    });
    expect(v.needs_review).toBe(false);
    expect(v.surface).toBe('test'); // higher weight than docs
  });

  it('honors a custom threshold', () => {
    const docsOnly = { filesChanged: ['docs/guide.md'] };
    expect(evaluateRiskFloor(docsOnly, 0.05).needs_review).toBe(true);
    expect(evaluateRiskFloor(docsOnly, DEFAULT_RISK_THRESHOLD).needs_review).toBe(false);
  });

  it('is deterministic across call order', () => {
    const a = evaluateRiskFloor({ filesChanged: ['a.md', 'auth/x.ts', 'b.tsx'] });
    const b = evaluateRiskFloor({ filesChanged: ['b.tsx', 'a.md', 'auth/x.ts'] });
    expect(a).toEqual(b);
  });
});
