/**
 * AI Context Formatter Tests
 */

import { formatAIContext } from '../ai-context'
import type { ScanResult, Vulnerability } from '../../types'

const createMockVulnerability = (overrides: Partial<Vulnerability> = {}): Vulnerability => ({
  id: 'test-vuln-1',
  filePath: 'src/api/users.ts',
  lineNumber: 42,
  lineContent: 'const query = `SELECT * FROM users WHERE id = ${userId}`',
  severity: 'high',
  category: 'sql_injection',
  title: 'SQL Injection Vulnerability',
  description: 'User input is directly concatenated into SQL query without parameterization.',
  suggestedFix: 'Use parameterized queries instead of string concatenation.',
  confidence: 'high',
  layer: 2,
  impact: 'Attackers can execute arbitrary SQL commands, potentially accessing or modifying all database records.',
  fixSteps: [
    'Replace string concatenation with parameterized query',
    'Use prepared statements or an ORM',
    'Validate and sanitize input data'
  ],
  references: ['https://owasp.org/www-community/attacks/SQL_Injection'],
  ...overrides,
})

const createMockScanResult = (vulnerabilities: Vulnerability[] = []): ScanResult => ({
  repoName: 'test-repo',
  repoUrl: 'https://github.com/test/test-repo',
  branch: 'main',
  filesScanned: 50,
  filesSkipped: 5,
  vulnerabilities,
  severityCounts: {
    critical: vulnerabilities.filter(v => v.severity === 'critical').length,
    high: vulnerabilities.filter(v => v.severity === 'high').length,
    medium: vulnerabilities.filter(v => v.severity === 'medium').length,
    low: vulnerabilities.filter(v => v.severity === 'low').length,
    info: vulnerabilities.filter(v => v.severity === 'info').length,
  },
  categoryCounts: {},
  hasBlockingIssues: vulnerabilities.some(v => v.severity === 'critical' || v.severity === 'high'),
  scanDuration: 1500,
  timestamp: '2024-01-15T10:30:00.000Z',
})

describe('formatAIContext', () => {
  it('should generate markdown with all sections', () => {
    const vuln = createMockVulnerability()
    const result = createMockScanResult([vuln])

    const output = formatAIContext(result)

    // Check header
    expect(output).toContain('<!-- OCULUM AI CONTEXT - AUTO-GENERATED -->')
    expect(output).toContain('# Security Issues Requiring Fixes')
    expect(output).toContain('**Repository:** test-repo')
    expect(output).toContain('**Findings:** 1')

    // Check instructions section
    expect(output).toContain('## Instructions for AI Assistants')
    expect(output).toContain('Address CRITICAL issues first, then HIGH')

    // Check finding details
    expect(output).toContain('## HIGH Issues')
    expect(output).toContain('SQL Injection Vulnerability')
    expect(output).toContain('`src/api/users.ts:42`')
    expect(output).toContain('sql_injection')

    // Check fix instructions
    expect(output).toContain('**Fix Instructions:**')
    expect(output).toContain('Replace string concatenation with parameterized query')

    // Check summary table
    expect(output).toContain('## Summary')
    expect(output).toContain('| Severity | Count | Files |')

    // Check footer
    expect(output).toContain('*Generated by Oculum Security Scanner*')
  })

  it('should order findings by severity (critical first)', () => {
    const critical = createMockVulnerability({
      id: 'critical-1',
      severity: 'critical',
      title: 'Critical Issue',
    })
    const high = createMockVulnerability({
      id: 'high-1',
      severity: 'high',
      title: 'High Issue',
    })
    const medium = createMockVulnerability({
      id: 'medium-1',
      severity: 'medium',
      title: 'Medium Issue',
    })
    const result = createMockScanResult([medium, critical, high])

    const output = formatAIContext(result)

    // Critical section should appear before High section
    const criticalIndex = output.indexOf('## CRITICAL Issues')
    const highIndex = output.indexOf('## HIGH Issues')
    const mediumIndex = output.indexOf('## MEDIUM Issues')

    expect(criticalIndex).toBeLessThan(highIndex)
    expect(highIndex).toBeLessThan(mediumIndex)
  })

  it('should include file:line locations', () => {
    const vuln = createMockVulnerability({
      filePath: 'src/controllers/auth.ts',
      lineNumber: 156,
    })
    const result = createMockScanResult([vuln])

    const output = formatAIContext(result)

    expect(output).toContain('`src/controllers/auth.ts:156`')
  })

  it('should include current code and fix instructions', () => {
    const vuln = createMockVulnerability({
      lineContent: 'eval(userInput)',
      fixSteps: [
        'Remove eval() usage',
        'Use a safe alternative like JSON.parse()',
        'Validate all user input'
      ],
    })
    const result = createMockScanResult([vuln])

    const output = formatAIContext(result)

    // Check code block
    expect(output).toContain('**Current Code:**')
    expect(output).toContain('eval(userInput)')

    // Check fix steps
    expect(output).toContain('**Fix Instructions:**')
    expect(output).toContain('1. Remove eval() usage')
    expect(output).toContain('2. Use a safe alternative like JSON.parse()')
    expect(output).toContain('3. Validate all user input')
  })

  it('should return minimal output for zero findings', () => {
    const result = createMockScanResult([])

    const output = formatAIContext(result)

    expect(output).toContain('<!-- OCULUM AI CONTEXT - AUTO-GENERATED -->')
    expect(output).toContain('# Security Issues Requiring Fixes')
    expect(output).toContain('**Findings:** 0')
    expect(output).toContain('No security issues found')
    // Should not have severity sections
    expect(output).not.toContain('## CRITICAL Issues')
    expect(output).not.toContain('## HIGH Issues')
  })

  it('should respect maxFindings option', () => {
    const vulnerabilities = Array.from({ length: 10 }, (_, i) =>
      createMockVulnerability({
        id: `vuln-${i}`,
        title: `Issue ${i + 1}`,
        severity: 'high',
      })
    )
    const result = createMockScanResult(vulnerabilities)

    const output = formatAIContext(result, { maxFindings: 3 })

    // Should only show 3 findings details
    expect(output).toContain('### 1. Issue')
    expect(output).toContain('### 2. Issue')
    expect(output).toContain('### 3. Issue')
    expect(output).not.toContain('### 4. Issue')

    // Should indicate more issues exist
    expect(output).toContain('7 more HIGH issues')
  })

  it('should include references when option is enabled', () => {
    const vuln = createMockVulnerability({
      references: [
        'https://owasp.org/www-community/attacks/SQL_Injection',
        'https://cwe.mitre.org/data/definitions/89.html',
      ],
    })
    const result = createMockScanResult([vuln])

    const output = formatAIContext(result, { includeReferences: true })

    expect(output).toContain('**References:**')
    expect(output).toContain('https://owasp.org/www-community/attacks/SQL_Injection')
    expect(output).toContain('https://cwe.mitre.org/data/definitions/89.html')
  })

  it('should include impact when available', () => {
    const vuln = createMockVulnerability({
      impact: 'Attackers can execute arbitrary SQL commands and access sensitive data.',
    })
    const result = createMockScanResult([vuln])

    const output = formatAIContext(result)

    expect(output).toContain('**Impact:**')
    expect(output).toContain('Attackers can execute arbitrary SQL commands')
  })

  it('should handle multiple files in summary', () => {
    const vulns = [
      createMockVulnerability({
        id: 'v1',
        filePath: 'src/api/users.ts',
        severity: 'critical',
      }),
      createMockVulnerability({
        id: 'v2',
        filePath: 'src/api/orders.ts',
        severity: 'critical',
      }),
      createMockVulnerability({
        id: 'v3',
        filePath: 'src/api/users.ts',
        severity: 'high',
      }),
    ]
    const result = createMockScanResult(vulns)

    const output = formatAIContext(result)

    // Summary table should list files
    expect(output).toContain('| Critical | 2 |')
    expect(output).toContain('src/api/users.ts')
    expect(output).toContain('src/api/orders.ts')
  })

  it('should use suggestedFix as fallback when fixSteps not available', () => {
    const vuln = createMockVulnerability({
      fixSteps: undefined,
      suggestedFix: 'Use parameterized queries instead of string concatenation.',
    })
    const result = createMockScanResult([vuln])

    const output = formatAIContext(result)

    expect(output).toContain('**Fix Instructions:**')
    expect(output).toContain('Use parameterized queries instead of string concatenation.')
  })
})
