// Test for ESLint plugin `no-hardcoded-spacing` (G2 — spacing half of §R2 token
// discipline) + the shared px↔token detection. Must catch the same cases as CLI
// probe R2S in scripts/audit-product-code.mjs. See ds-enforcement-scenarios-spec.md §4.

import { describe, expect, it } from 'vitest'
import { Linter } from 'eslint'
import vueParser from 'vue-eslint-parser'
// @ts-expect-error — plain ESM JS plugin without .d.ts
import tvuPlugin from '../eslint-plugin/index.js'
// @ts-expect-error — plain ESM JS module without .d.ts
import { findSpacingViolations } from '../eslint-plugin/spacing-token-map.js'

function lintVue(code: string) {
  const linter = new Linter()
  return linter.verify(
    code,
    {
      files: ['**/*.vue'],
      languageOptions: { parser: vueParser as any, ecmaVersion: 'latest', sourceType: 'module' },
      plugins: { '@nancyzeng0210/tvu-design-system': tvuPlugin as any },
      rules: { '@nancyzeng0210/tvu-design-system/no-hardcoded-spacing': 'error' },
    },
    { filename: 'test.vue' }
  )
}

describe('spacing-token-map / findSpacingViolations (FP discipline)', () => {
  it('flags spacing px with a token equivalent', () => {
    expect(findSpacingViolations('padding: 16px').map((v: any) => v.token)).toEqual(['--sp-m'])
    expect(findSpacingViolations('gap: 12px;')[0].token).toBe('--sp-s')
    expect(findSpacingViolations('margin-top: 8px')[0].token).toBe('--sp-xs')
  })
  it('flags radius px with a token equivalent', () => {
    expect(findSpacingViolations('border-radius: 8px')[0].token).toBe('--r-m')
    expect(findSpacingViolations('border-radius: 100px')[0].token).toBe('--r-xxl')
  })
  it('flags Tailwind arbitrary spacing/radius', () => {
    expect(findSpacingViolations('class="p-[16px]"')[0].token).toBe('--sp-m')
    expect(findSpacingViolations('rounded-[8px]')[0].token).toBe('--r-m')
  })
  it('does NOT flag arbitrary px / non-spacing props / no-token values', () => {
    expect(findSpacingViolations('width: 16px')).toEqual([]) // not a spacing prop
    expect(findSpacingViolations('border: 1px solid #ccc')).toEqual([]) // border-width not scanned
    expect(findSpacingViolations('padding: 10px')).toEqual([]) // 10 has no token
    expect(findSpacingViolations('border-radius: 24px')).toEqual([]) // 24 has no radius token
    expect(findSpacingViolations('padding: 2px')).toEqual([]) // 2 is radius-only, not spacing
    expect(findSpacingViolations('font-size: 16px; line-height: 24px')).toEqual([])
    expect(findSpacingViolations('top: 8px; left: 12px')).toEqual([]) // positioning not scanned
  })
  it('handles shorthand with multiple values', () => {
    const v = findSpacingViolations('padding: 8px 16px')
    expect(v.map((x: any) => x.token).sort()).toEqual(['--sp-m', '--sp-xs'])
  })
})

describe('eslint-plugin / no-hardcoded-spacing', () => {
  it('flags inline style padding in template', () => {
    const msgs = lintVue(`<template><div style="padding: 16px">x</div></template>`)
    expect(msgs.some((m) => m.messageId === 'hardcodedSpacing')).toBe(true)
  })
  it('flags Tailwind arbitrary class in template', () => {
    const msgs = lintVue(`<template><div class="p-[8px] rounded-[8px]">x</div></template>`)
    expect(msgs.filter((m) => m.messageId === 'hardcodedSpacing').length).toBe(2)
  })
  it('flags CSS-in-JS template literal', () => {
    const msgs = lintVue('<template><div>x</div></template><script>const s = `gap: 12px;`</script>')
    expect(msgs.some((m) => m.messageId === 'hardcodedSpacing')).toBe(true)
  })
  it('does not flag arbitrary px (width/border/no-token)', () => {
    const msgs = lintVue(`<template><div style="width: 16px; border: 1px solid; padding: 10px">x</div></template>`)
    expect(msgs.filter((m) => m.messageId === 'hardcodedSpacing')).toEqual([])
  })
  it('clean template passes', () => {
    const msgs = lintVue(`<template><div style="padding: var(--sp-m)">x</div></template>`)
    expect(msgs).toEqual([])
  })
})
