// permission.test.mjs — Integration tests for the permission-mapper
// Tests against the evil-project-health fixture which has plugin.fixture.json.
//
// The scanner's isPlugin() checks:
//   1. .claude-plugin/plugin.json
//   2. plugin.json
//   3. plugin.fixture.json   ← evil-project-health has this
//
// So the fixture IS detected as a plugin and the scanner should return status 'ok'.

import { describe, it, beforeEach } from 'node:test';
import assert from 'node:assert/strict';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { resetCounter } from '../../scanners/lib/output.mjs';
import { scan } from '../../scanners/permission-mapper.mjs';

const __dirname = fileURLToPath(new URL('.', import.meta.url));
const FIXTURE = resolve(__dirname, '../../examples/malicious-skill-demo/evil-project-health');

describe('permission-mapper integration', () => {
  beforeEach(() => {
    resetCounter();
  });

  it('returns status ok or skipped (graceful handling)', async () => {
    // The fixture has plugin.fixture.json, which the scanner recognises.
    // If the scanner detects it as a plugin → 'ok'.
    // If the scanner does not recognise .fixture.json → 'skipped' (also valid).
    const result = await scan(FIXTURE, { files: [] });
    const validStatuses = ['ok', 'skipped'];
    assert.ok(
      validStatuses.includes(result.status),
      `Expected status 'ok' or 'skipped', got '${result.status}'`
    );
  });

  it('returns ok and finds permission issues when plugin is detected', async () => {
    const result = await scan(FIXTURE, { files: [] });

    if (result.status === 'skipped') {
      // Scanner does not recognise .fixture.json suffix — acceptable, skip checks
      assert.equal(result.findings.length, 0, 'skipped result should have 0 findings');
      return;
    }

    // Status is 'ok' — fixture contains components with tool mismatches
    assert.equal(result.status, 'ok');
    // The SKILL.fixture.md has Read, Glob, Grep, Bash, Write, WebFetch with scan/audit intent
    // Expect at least 1 finding (purpose-tools mismatch or dangerous combo)
    assert.ok(
      result.findings.length >= 1,
      `Expected >= 1 permission finding, got ${result.findings.length}`
    );
  });

  it('all findings have DS-PRM- prefix when present', async () => {
    const result = await scan(FIXTURE, { files: [] });
    if (result.status === 'skipped') return;

    const wrongPrefix = result.findings.filter(f => !f.id.startsWith('DS-PRM-'));
    assert.equal(
      wrongPrefix.length, 0,
      `All permission findings should have DS-PRM- prefix. Wrong: ${wrongPrefix.map(f => f.id).join(', ')}`
    );
  });

  it('reports owasp LLM06 for permission findings', async () => {
    const result = await scan(FIXTURE, { files: [] });
    if (result.status === 'skipped') return;

    for (const f of result.findings) {
      assert.equal(f.owasp, 'LLM06', `Finding ${f.id} should be OWASP LLM06, got ${f.owasp}`);
    }
  });

  it('scanner name is permission-mapper', async () => {
    const result = await scan(FIXTURE, { files: [] });
    assert.equal(result.scanner, 'PRM');
  });

  it('counts object keys contain critical, high, medium, low, info', async () => {
    const result = await scan(FIXTURE, { files: [] });
    const expectedKeys = ['critical', 'high', 'medium', 'low', 'info'];
    for (const key of expectedKeys) {
      assert.ok(key in result.counts, `counts should have key '${key}'`);
    }
  });

  it('non-plugin directory returns skipped with no findings', async () => {
    // Use the lib/ subdirectory which has no plugin structure
    const libDir = resolve(FIXTURE, 'lib');
    resetCounter();
    const result = await scan(libDir, { files: [] });
    assert.equal(result.status, 'skipped', `Expected skipped for non-plugin dir, got ${result.status}`);
    assert.equal(result.findings.length, 0, 'Non-plugin dir should produce 0 findings');
  });
});
