import { describe, it, expect } from 'vitest'
// @ts-expect-error — plain JS ESM audit script, no types
import { classifyBindingViolations } from '../scripts/audit-mockup-binding-fidelity.mjs'

const scale = { spacing: new Set([4, 8, 12, 16, 24, 32, 40, 56]), radius: new Set([2, 4, 8, 12, 16, 20]) }

// helper: minimal Figma-REST-shaped node tree
function tree(children: any[], extra: any = {}) {
  return { id: '0', type: 'FRAME', name: 'root', children, ...extra }
}

describe('classifyBindingViolations — D16 (§M49.1 + §C5)', () => {
  const grey = new Map([['g', 'UX/Grey/grey-6'], ['sem', 'Color Type/Text/Tips']])

  it('B-SEM: flags TEXT fill bound to a grey primitive (semantic exists)', () => {
    const t = tree([{ id: 't', type: 'TEXT', name: 'label', style: { fontSize: 14 }, styles: { text: 'S1' }, fills: [{ boundVariables: { color: { id: 'g' } } }] }])
    const r = classifyBindingViolations(t, {}, grey, scale)
    expect(r.bSem.map((v: any) => v.nodeId)).toEqual(['t'])
  })

  it('B-SEM: does NOT flag TEXT bound to a semantic Color Type variable', () => {
    const t = tree([{ id: 't', type: 'TEXT', name: 'label', style: { fontSize: 14 }, styles: { text: 'S1' }, fills: [{ boundVariables: { color: { id: 'sem' } } }] }])
    expect(classifyBindingViolations(t, {}, grey, scale).bSem).toEqual([])
  })

  it('B-TYPO: flags a TEXT node with no text style applied (raw fontSize)', () => {
    const t = tree([{ id: 't', type: 'TEXT', name: 'x', style: { fontSize: 20 }, fills: [] }])
    expect(classifyBindingViolations(t, {}, grey, scale).bTypo.map((v: any) => v.nodeId)).toEqual(['t'])
  })

  it('B-TYPO: does NOT flag a TEXT node that has a text style applied', () => {
    const t = tree([{ id: 't', type: 'TEXT', name: 'x', style: { fontSize: 20 }, styles: { text: 'S1' }, fills: [] }])
    expect(classifyBindingViolations(t, {}, grey, scale).bTypo).toEqual([])
  })

  it('B-EFFECT: flags visible effects with no effect style applied', () => {
    const t = tree([{ id: 'r', type: 'RECTANGLE', name: 'box', effects: [{ type: 'DROP_SHADOW', visible: true }] }])
    expect(classifyBindingViolations(t, {}, grey, scale).bEffect.map((v: any) => v.nodeId)).toEqual(['r'])
  })

  it('B-SCALE: flags off-scale raw spacing not bound to a variable', () => {
    const r = classifyBindingViolations(tree([], { itemSpacing: 18 }), {}, grey, scale)
    expect(r.bScale.map((v: any) => `${v.prop}=${v.value}`)).toContain('itemSpacing=18')
  })

  it('B-SCALE: does NOT flag an on-scale spacing value', () => {
    expect(classifyBindingViolations(tree([], { itemSpacing: 16 }), {}, grey, scale).bScale).toEqual([])
  })

  it('B-SCALE: does NOT flag an off-scale value that is bound to a variable (e.g. pill radius)', () => {
    const r = classifyBindingViolations(tree([], { cornerRadius: 100, boundVariables: { topLeftRadius: { id: 'rv' } } }), {}, grey, scale)
    expect(r.bScale).toEqual([])
  })
})
