// Test for ESLint plugin `no-native-element` (G1 — code-side R15 enforcement).
// Forbids hand-rolled native <button>/<input>/<select>/<textarea> when the TVU
// DS ships an equivalent; must catch the same cases as CLI R15 in
// scripts/audit-product-code.mjs. See docs/internal/ds-enforcement-scenarios-spec.md.

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'

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-native-element': 'error',
      },
    },
    { filename: 'test.vue' }
  )
}

describe('eslint-plugin / no-native-element (R15)', () => {
  describe('flags native controls in Vue <template>', () => {
    for (const tag of ['button', 'input', 'select', 'textarea']) {
      it(`flags <${tag}>`, () => {
        const code =
          tag === 'input'
            ? `<template><input type="text" /></template>`
            : `<template><${tag}>x</${tag}></template>`
        const msgs = lintVue(code)
        expect(msgs.some((m) => m.messageId === 'nativeElement')).toBe(true)
      })
    }

    it('flags hand-rolled button with classes (owner pain case)', () => {
      const code = `<template><button class="bg-green-500 px-4 py-2 rounded-full">Confirm</button></template>`
      const msgs = lintVue(code)
      expect(msgs.some((m) => m.messageId === 'nativeElement')).toBe(true)
    })

    it('flags native <select> used as a dropdown', () => {
      const code = `<template><select><option>a</option></select></template>`
      const msgs = lintVue(code)
      expect(msgs.filter((m) => m.messageId === 'nativeElement').length).toBe(1)
    })
  })

  describe('does not flag (no DS equivalent / canonical components)', () => {
    it('passes <input type="hidden">', () => {
      const msgs = lintVue(`<template><input type="hidden" name="csrf" /></template>`)
      expect(msgs).toEqual([])
    })

    it('passes <input type="file">', () => {
      const msgs = lintVue(`<template><input type="file" /></template>`)
      expect(msgs).toEqual([])
    })

    it('passes canonical PascalCase components', () => {
      const code = `<template><Button>Confirm</Button><SelectBoxLine :options="o" /></template>`
      const msgs = lintVue(code)
      expect(msgs).toEqual([])
    })

    it('clean template passes', () => {
      const msgs = lintVue(`<template><div>Hello</div></template>`)
      expect(msgs).toEqual([])
    })
  })

  // Escape (consumer-facing): in real Vue projects `<!-- eslint-disable-next-line
  // @nancyzeng0210/tvu-design-system/no-native-element -->` works via eslint-plugin-vue's
  // processor (which wires vue-eslint-parser's template directives). This is the same escape
  // story as every other template-body rule in this plugin (no-inline-svg / no-hardcoded-color)
  // and can't be exercised through raw Linter.verify without that processor, so it isn't unit-
  // tested here. The CLI mirror's escapes (`<!-- LIBRARY GAP: ... -->` / `// AUDIT-IGNORE-R15`)
  // are deterministic and covered by the audit-product-code self-test.
})
