import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import {
  generatePostureReport,
  generateDriftReport,
  generatePluginHealthReport,
  generateFullReport,
} from '../../scanners/lib/report-generator.mjs';

// --- Helpers ---

function makePostureResult(overrides = {}) {
  return {
    utilization: { score: 65, overhang: 35 },
    maturity: { level: 2, name: 'Structured', description: 'Rules, skills, hooks' },
    segment: { segment: 'Strong', description: 'Well-configured' },
    areas: [
      { name: 'CLAUDE.md', grade: 'A', score: 95, findingCount: 0 },
      { name: 'Settings', grade: 'B', score: 80, findingCount: 2 },
      { name: 'Hooks', grade: 'C', score: 60, findingCount: 4 },
    ],
    overallGrade: 'B',
    topActions: ['Add MCP server', 'Configure hooks diversity', 'Add custom skills'],
    scannerEnvelope: {
      meta: { target: '/test/project', timestamp: '2026-04-03T12:00:00.000Z', version: '2.0.0', tool: 'config-audit' },
      scanners: [
        { scanner: 'CML', findings: [], counts: { critical: 0, high: 0, medium: 0, low: 0, info: 0 } },
        { scanner: 'SET', findings: [
          { severity: 'medium', title: 'Unknown key', file: 'settings.json' },
          { severity: 'low', title: 'Missing schema', file: 'settings.json' },
        ], counts: { critical: 0, high: 0, medium: 1, low: 1, info: 0 } },
      ],
    },
    ...overrides,
  };
}

function makeDiffResult(overrides = {}) {
  return {
    summary: { totalBefore: 10, totalAfter: 8, newCount: 1, resolvedCount: 3, trend: 'improving' },
    scoreChange: {
      before: { score: 60, grade: 'C' },
      after: { score: 75, grade: 'B' },
      delta: 15,
    },
    newFindings: [
      { severity: 'medium', title: 'New finding', file: 'test.json' },
    ],
    resolvedFindings: [
      { severity: 'high', title: 'Fixed issue' },
      { severity: 'medium', title: 'Another fixed' },
      { severity: 'low', title: 'Minor fix' },
    ],
    areaChanges: [
      { name: 'Settings', before: { score: 60, grade: 'C' }, after: { score: 80, grade: 'B' }, delta: 20 },
      { name: 'Hooks', before: { score: 70, grade: 'B' }, after: { score: 70, grade: 'B' }, delta: 0 },
    ],
    ...overrides,
  };
}

function makePluginResults() {
  return [
    { name: 'plugin-a', findings: [], commandCount: 5, agentCount: 2 },
    { name: 'plugin-b', findings: [
      { severity: 'medium', title: 'Missing frontmatter' },
      { severity: 'low', title: 'No README' },
    ], commandCount: 3, agentCount: 1 },
  ];
}

function makeScanResult(crossPluginFindings = []) {
  return {
    scanner: 'PLH',
    status: 'ok',
    findings: [...crossPluginFindings],
    counts: { critical: 0, high: 0, medium: 0, low: 0, info: 0 },
  };
}

// ========================================
// generatePostureReport
// ========================================
describe('generatePostureReport', () => {
  it('returns markdown with health header and grade', () => {
    const report = generatePostureReport(makePostureResult());
    assert.ok(report.includes('## Health Assessment'));
    assert.ok(report.includes('Health Grade'));
    assert.ok(report.includes('**B**'));
  });

  it('includes area breakdown table (quality areas only)', () => {
    const report = generatePostureReport(makePostureResult());
    assert.ok(report.includes('| CLAUDE.md |'));
    assert.ok(report.includes('| Settings |'));
    assert.ok(report.includes('| Hooks |'));
  });

  it('excludes Feature Coverage from area breakdown', () => {
    const result = makePostureResult({
      areas: [
        { name: 'CLAUDE.md', grade: 'A', score: 95, findingCount: 0 },
        { name: 'Feature Coverage', grade: 'F', score: 20, findingCount: 15 },
      ],
    });
    const report = generatePostureReport(result);
    assert.ok(!report.includes('| Feature Coverage |'));
    assert.ok(report.includes('| CLAUDE.md |'));
  });

  it('shows opportunity count when present', () => {
    const report = generatePostureReport(makePostureResult({ opportunityCount: 5 }));
    assert.ok(report.includes('5 features available'));
  });

  it('does not show legacy metrics (utilization, maturity, segment)', () => {
    const report = generatePostureReport(makePostureResult());
    assert.ok(!report.includes('Utilization'));
    assert.ok(!report.includes('Maturity'));
    assert.ok(!report.includes('Segment'));
  });

  it('includes scanner findings in collapsed details', () => {
    const report = generatePostureReport(makePostureResult());
    assert.ok(report.includes('<details>'));
    assert.ok(report.includes('SET'));
    assert.ok(report.includes('Unknown key'));
  });

  it('skips scanners with no findings', () => {
    const report = generatePostureReport(makePostureResult());
    // CML has 0 findings, should not appear in details
    assert.ok(!report.includes('<summary>CML'));
  });

  it('handles empty areas', () => {
    const report = generatePostureReport(makePostureResult({ areas: [], topActions: [] }));
    assert.ok(report.includes('## Health Assessment'));
  });
});

// ========================================
// generateDriftReport
// ========================================
describe('generateDriftReport', () => {
  it('returns markdown with baseline info', () => {
    const report = generateDriftReport(makeDiffResult(), 'my-baseline');
    assert.ok(report.includes('## Drift Report'));
    assert.ok(report.includes('my-baseline'));
  });

  it('shows trend indicator', () => {
    const report = generateDriftReport(makeDiffResult(), 'default');
    assert.ok(report.includes('Improving'));
  });

  it('shows score delta', () => {
    const report = generateDriftReport(makeDiffResult(), 'default');
    assert.ok(report.includes('+15'));
  });

  it('shows new findings table', () => {
    const report = generateDriftReport(makeDiffResult(), 'default');
    assert.ok(report.includes('New Findings'));
    assert.ok(report.includes('New finding'));
  });

  it('shows resolved findings table', () => {
    const report = generateDriftReport(makeDiffResult(), 'default');
    assert.ok(report.includes('Resolved Findings'));
    assert.ok(report.includes('Fixed issue'));
  });

  it('shows area changes (only non-zero delta)', () => {
    const report = generateDriftReport(makeDiffResult(), 'default');
    assert.ok(report.includes('Settings'));
    // Hooks has delta 0, should not appear
    assert.ok(!report.includes('| Hooks |'));
  });
});

// ========================================
// generatePluginHealthReport
// ========================================
describe('generatePluginHealthReport', () => {
  it('returns markdown with plugin table', () => {
    const report = generatePluginHealthReport(makeScanResult(), makePluginResults());
    assert.ok(report.includes('## Plugin Health'));
    assert.ok(report.includes('plugin-a'));
    assert.ok(report.includes('plugin-b'));
  });

  it('shows grades and counts', () => {
    const report = generatePluginHealthReport(makeScanResult(), makePluginResults());
    assert.ok(report.includes('| 5 |'));
    assert.ok(report.includes('| 3 |'));
  });

  it('includes per-plugin findings', () => {
    const report = generatePluginHealthReport(makeScanResult(), makePluginResults());
    assert.ok(report.includes('Missing frontmatter'));
  });

  it('handles no plugins', () => {
    const report = generatePluginHealthReport(makeScanResult(), []);
    assert.ok(report.includes('No plugins found'));
  });

  it('shows cross-plugin issues', () => {
    const crossFindings = [
      { severity: 'high', title: 'Cross-plugin conflict', description: 'Command name clash' },
    ];
    const report = generatePluginHealthReport(makeScanResult(crossFindings), makePluginResults());
    assert.ok(report.includes('Cross-Plugin Issues'));
    assert.ok(report.includes('Command name clash'));
  });
});

// ========================================
// generateFullReport
// ========================================
describe('generateFullReport', () => {
  it('combines all sections', () => {
    const report = generateFullReport(
      makePostureResult(),
      { diff: makeDiffResult(), baselineName: 'default' },
      { scanResult: makeScanResult(), pluginResults: makePluginResults() },
    );
    assert.ok(report.includes('# Config-Audit Report'));
    assert.ok(report.includes('## Health Assessment'));
    assert.ok(report.includes('## Drift Report'));
    assert.ok(report.includes('## Plugin Health'));
  });

  it('skips null sections', () => {
    const report = generateFullReport(makePostureResult(), null, null);
    assert.ok(report.includes('## Health Assessment'));
    assert.ok(!report.includes('## Drift Report'));
    assert.ok(!report.includes('## Plugin Health'));
  });

  it('handles all null inputs', () => {
    const report = generateFullReport(null, null, null);
    assert.ok(report.includes('No data provided'));
  });

  it('stays under 500 lines', () => {
    const report = generateFullReport(makePostureResult(), null, null);
    const lineCount = report.split('\n').length;
    assert.ok(lineCount <= 502); // 500 + truncation notice
  });
});
