// Smoke tests for CSP report normalization.
//
// Verifies:
//   - legacy `{ csp-report: {...} }` shape (Safari, older Firefox) parses
//   - Reporting API array shape (Chrome, Edge) parses
//   - browser extension noise drops to `low signal`
//   - oversized strings get clipped
//   - junk payloads return an empty array (caller logs at debug, not warn)

import { describe, it, expect } from 'vitest'
import {
  normalizeCspReportBody,
  isLowSignalReport,
} from '@/lib/security'

describe('normalizeCspReportBody — legacy shape', () => {
  it('parses a single-report legacy body', () => {
    const raw = {
      'csp-report': {
        'document-uri': 'https://app.example.com/dashboard',
        'referrer': 'https://app.example.com/login',
        'violated-directive': 'script-src-elem',
        'effective-directive': 'script-src-elem',
        'original-policy': "default-src 'self'; script-src 'self' 'nonce-abc'",
        'blocked-uri': 'https://evil.example.com/x.js',
        'source-file': 'https://app.example.com/page',
        'line-number': 42,
        'column-number': 7,
        'status-code': 200,
        'disposition': 'report',
      },
    }

    const [normalized] = normalizeCspReportBody(raw)

    expect(normalized).toBeDefined()
    expect(normalized.payloadShape).toBe('legacy')
    expect(normalized.effectiveDirective).toBe('script-src-elem')
    expect(normalized.blockedUri).toBe('https://evil.example.com/x.js')
    expect(normalized.documentUri).toBe('https://app.example.com/dashboard')
    expect(normalized.lineNumber).toBe(42)
    expect(normalized.columnNumber).toBe(7)
    expect(normalized.disposition).toBe('report')
    expect(normalized.reportAgeMs).toBeNull()
  })

  it('falls back to violated-directive when effective-directive is missing', () => {
    const raw = {
      'csp-report': {
        'violated-directive': 'img-src',
        'blocked-uri': 'https://cdn.example.com/x.png',
      },
    }
    const [normalized] = normalizeCspReportBody(raw)
    expect(normalized.effectiveDirective).toBe('img-src')
  })

  it('accepts the flat legacy shape some intermediaries produce', () => {
    const raw = {
      'violated-directive': 'connect-src',
      'blocked-uri': 'wss://evil.example.com/s',
    }
    const reports = normalizeCspReportBody(raw)
    expect(reports.length).toBe(1)
    expect(reports[0].payloadShape).toBe('legacy')
    expect(reports[0].effectiveDirective).toBe('connect-src')
  })
})

describe('normalizeCspReportBody — Reporting API shape', () => {
  it('parses a Reporting API array with one record', () => {
    const raw = [
      {
        type: 'csp-violation',
        age: 120,
        url: 'https://app.example.com/project/abc',
        user_agent: 'Mozilla/5.0',
        body: {
          effectiveDirective: 'script-src',
          blockedURL: 'https://tracker.example.com/t.js',
          documentURL: 'https://app.example.com/project/abc',
          originalPolicy: "default-src 'self'",
          sourceFile: 'https://app.example.com/page',
          lineNumber: 1,
          columnNumber: 2,
          statusCode: 200,
          disposition: 'enforce',
          referrer: '',
        },
      },
    ]

    const [normalized] = normalizeCspReportBody(raw)

    expect(normalized.payloadShape).toBe('reporting-api')
    expect(normalized.effectiveDirective).toBe('script-src')
    expect(normalized.blockedUri).toBe('https://tracker.example.com/t.js')
    expect(normalized.disposition).toBe('enforce')
    expect(normalized.reportAgeMs).toBe(120)
    expect(normalized.reportType).toBe('csp-violation')
  })

  it('falls back to the wrapper url when body.documentURL is missing', () => {
    const raw = [
      {
        type: 'csp-violation',
        age: 0,
        url: 'https://app.example.com/fallback',
        body: { effectiveDirective: 'img-src', blockedURL: 'data:' },
      },
    ]
    const [normalized] = normalizeCspReportBody(raw)
    expect(normalized.documentUri).toBe('https://app.example.com/fallback')
  })

  it('filters non-object entries out of the Reporting API array', () => {
    const raw = [
      null,
      'not-an-object',
      { type: 'csp-violation', age: 0, url: 'https://x', body: { blockedURL: 'y' } },
    ]
    const reports = normalizeCspReportBody(raw)
    expect(reports.length).toBe(1)
    expect(reports[0].blockedUri).toBe('y')
  })
})

describe('normalizeCspReportBody — rejects garbage', () => {
  it('returns [] for null', () => {
    expect(normalizeCspReportBody(null)).toEqual([])
  })
  it('returns [] for undefined', () => {
    expect(normalizeCspReportBody(undefined)).toEqual([])
  })
  it('returns [] for a plain object without csp-report or directive keys', () => {
    expect(normalizeCspReportBody({ hello: 'world' })).toEqual([])
  })
  it('returns [] for a string', () => {
    expect(normalizeCspReportBody('malformed')).toEqual([])
  })
})

describe('normalizeCspReportBody — clipping', () => {
  it('clips oversized blocked-uri strings', () => {
    const huge = 'https://evil.example.com/' + 'x'.repeat(10_000)
    const [normalized] = normalizeCspReportBody({
      'csp-report': { 'blocked-uri': huge, 'violated-directive': 'img-src' },
    })
    expect(normalized.blockedUri).not.toBeNull()
    expect(normalized.blockedUri!.length).toBeLessThanOrEqual(4096 + '…[clipped]'.length)
    expect(normalized.blockedUri!.endsWith('[clipped]')).toBe(true)
  })
})

describe('isLowSignalReport', () => {
  it('flags chrome-extension blocked URIs as low signal', () => {
    const [normalized] = normalizeCspReportBody({
      'csp-report': {
        'violated-directive': 'script-src',
        'blocked-uri': 'chrome-extension://abc/content.js',
      },
    })
    expect(isLowSignalReport(normalized)).toBe(true)
  })

  it('flags moz-extension source files as low signal', () => {
    const [normalized] = normalizeCspReportBody({
      'csp-report': {
        'violated-directive': 'script-src',
        'blocked-uri': 'inline',
        'source-file': 'moz-extension://abc/shim.js',
      },
    })
    expect(isLowSignalReport(normalized)).toBe(true)
  })

  it('does NOT flag real https blocked URIs as low signal', () => {
    const [normalized] = normalizeCspReportBody({
      'csp-report': {
        'violated-directive': 'script-src',
        'blocked-uri': 'https://tracker.example.com/t.js',
      },
    })
    expect(isLowSignalReport(normalized)).toBe(false)
  })

  it('flags the bare `about` blocked-uri (bfcache probes)', () => {
    const [normalized] = normalizeCspReportBody({
      'csp-report': {
        'violated-directive': 'default-src',
        'blocked-uri': 'about',
      },
    })
    expect(isLowSignalReport(normalized)).toBe(true)
  })
})
