// tests/audit-prop-naming.test.ts
// INFRA-F59 TDD: write FIRST (RED), then implement findViolations in audit-prop-naming.mjs (GREEN).
import { describe, it, expect } from 'vitest'
import { findViolations } from '../scripts/audit-prop-naming.mjs'

// Minimal SoT fixture — mirrors prop-naming-conventions.json
const SOT = {
  conventions: { fill: 'fill', kind: 'type', color: 'color', state: 'state', size: 'size' },
  blocklist: ['style', 'variant', 'canonicalStyle'],
  blocklistPatterns: ['^property\\d+$'],
  sizeCasing: { allowed: ['XS', 'S', 'M', 'L', 'XL'] },
}

// Helper: wrap prop array into minimal ComponentConfig shape
function cfg(name: string, props: object[]) {
  return [{ name, props }]
}

describe('findViolations — blocklist', () => {
  it('flags prop named "style" (footgun)', () => {
    const v = findViolations(cfg('Button', [{ name: 'style', tsType: 'string' }]), SOT)
    expect(v.length).toBeGreaterThan(0)
    expect(v[0].kind).toBe('blocklist')
    expect(v[0].prop).toBe('style')
  })

  it('flags prop matching blocklistPattern ^property\\d+$', () => {
    const v = findViolations(cfg('Foo', [{ name: 'property1', tsType: 'string' }]), SOT)
    expect(v.length).toBeGreaterThan(0)
    expect(v[0].kind).toBe('blocklist')
    expect(v[0].prop).toBe('property1')
  })

  it('flags "variant" (old remap name)', () => {
    const v = findViolations(cfg('Bar', [{ name: 'variant', tsType: 'string' }]), SOT)
    expect(v.length).toBeGreaterThan(0)
    expect(v[0].kind).toBe('blocklist')
  })
})

describe('findViolations — concept consistency (axis)', () => {
  it('flags axis="fill" when prop name is "variant"', () => {
    const v = findViolations(cfg('Button', [{ name: 'variant', axis: 'fill', tsType: `'a'|'b'` }]), SOT)
    // variant hits blocklist AND concept; at least one concept violation expected
    const conceptV = v.filter(x => x.kind === 'concept')
    expect(conceptV.length).toBeGreaterThan(0)
    expect(conceptV[0].msg).toContain('fill')
  })

  it('flags axis="kind" when prop name is "shape"', () => {
    const v = findViolations(cfg('Badge', [{ name: 'shape', axis: 'kind', tsType: `'a'|'b'` }]), SOT)
    const conceptV = v.filter(x => x.kind === 'concept')
    expect(conceptV.length).toBe(1)
    expect(conceptV[0].msg).toContain('"type"')
  })

  it('passes axis="fill" with name="fill"', () => {
    const v = findViolations(cfg('Button', [{ name: 'fill', axis: 'fill', tsType: `'a'|'b'` }]), SOT)
    expect(v.filter(x => x.kind === 'concept').length).toBe(0)
  })

  it('passes axis="kind" with name="type"', () => {
    const v = findViolations(cfg('Badge', [{ name: 'type', axis: 'kind', tsType: `'a'|'b'` }]), SOT)
    expect(v.filter(x => x.kind === 'concept').length).toBe(0)
  })
})

describe('findViolations — size casing', () => {
  it('flags lowercase size values', () => {
    const v = findViolations(cfg('Input', [{ name: 'size', tsType: `'m' | 'l'` }]), SOT)
    const sizeV = v.filter(x => x.kind === 'size-casing')
    expect(sizeV.length).toBe(1)
    expect(sizeV[0].msg).toContain('m')
    expect(sizeV[0].msg).toContain('l')
  })

  it('passes uppercase size values', () => {
    const v = findViolations(cfg('Input', [{ name: 'size', tsType: `'M' | 'L' | 'XL'` }]), SOT)
    expect(v.filter(x => x.kind === 'size-casing').length).toBe(0)
  })
})

describe('findViolations — clean fixture', () => {
  it('returns 0 violations for a well-named component', () => {
    const configs = cfg('Button', [
      { name: 'fill',  tsType: `'filling' | 'ghost'`, axis: 'fill' },
      { name: 'size',  tsType: `'S' | 'M' | 'L'` },
      { name: 'color', tsType: `'gray' | 'green'` },
    ])
    expect(findViolations(configs, SOT).length).toBe(0)
  })
})
