import { describe, it, expect } from 'vitest'
import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { dirname, resolve } from 'node:path'
import { lintMockupHtml } from '../scripts/audit-mockup-html-conformance.mjs'

const __dirname = dirname(fileURLToPath(import.meta.url))
const FIXTURES = resolve(__dirname, 'fixtures/mockup-html-conformance')
const read = (name: string) => readFileSync(resolve(FIXTURES, name), 'utf8')

function byRule(findings: ReturnType<typeof lintMockupHtml>) {
  return findings.reduce<Record<string, number>>((acc, f) => {
    acc[f.rule] = (acc[f.rule] ?? 0) + 1
    return acc
  }, {})
}

describe('mockup-html-conformance linter', () => {
  it('passes a conformant mockup with zero findings', () => {
    const findings = lintMockupHtml(read('pass.html'))
    expect(findings).toEqual([])
  })

  it('flags each first-batch violation in a non-conformant mockup', () => {
    const findings = lintMockupHtml(read('fail.html'))
    const counts = byRule(findings)
    expect(counts['popupbox-for-confirm']).toBeGreaterThanOrEqual(1)
    expect(counts['unconstrained-svg']).toBeGreaterThanOrEqual(1)
    expect(counts['handrolled-nav']).toBeGreaterThanOrEqual(2) // <nav> + nav-classed <ul>
    expect(counts['hardcoded-color']).toBeGreaterThanOrEqual(2)
    expect(counts['alert-confirmText']).toBeGreaterThanOrEqual(1)
  })

  it('classifies severities: rules 1-3 error, rules 4-5 warn', () => {
    const findings = lintMockupHtml(read('fail.html'))
    const sev = (rule: string) => findings.find((f) => f.rule === rule)?.severity
    expect(sev('popupbox-for-confirm')).toBe('error')
    expect(sev('unconstrained-svg')).toBe('error')
    expect(sev('handrolled-nav')).toBe('error')
    expect(sev('hardcoded-color')).toBe('warn')
    expect(sev('alert-confirmText')).toBe('warn')
  })

  it('does not flag a template-interpolated svg class (JS mockup icon helper)', () => {
    const html = '<style>.ico{width:12px;height:12px}</style>' +
      '<script>const t=`<svg class="${cls}"><use href="#x"></use></svg>`</script>'
    expect(lintMockupHtml(html).filter((f) => f.rule === 'unconstrained-svg')).toEqual([])
  })

  it('allows pure-neutral scaffolding backdrops but flags off-token color', () => {
    const html = '<style>#stage{background:#000}.card{background:#3a3a3a}</style>'
    const hc = lintMockupHtml(html).filter((f) => f.rule === 'hardcoded-color')
    expect(hc).toHaveLength(1)
    expect(hc[0].message).toContain('#3a3a3a')
  })

  it('honors inline suppression on the next line', () => {
    const html = [
      '<!-- mockup-lint-disable-next-line unconstrained-svg intentional decorative -->',
      '<svg viewBox="0 0 24 24"><path d="M0 0h24v24"></path></svg>',
    ].join('\n')
    expect(lintMockupHtml(html).filter((f) => f.rule === 'unconstrained-svg')).toEqual([])
  })

  it('does not flag PopupBox that wraps a real form (large custom modal)', () => {
    const html = '<tvu-popup-box><form><input name="t"><button>Cancel</button></form></tvu-popup-box>'
    expect(lintMockupHtml(html).filter((f) => f.rule === 'popupbox-for-confirm')).toEqual([])
  })

  it('does not flag nav when MenuList is present', () => {
    const html = '<tvu-menu-list></tvu-menu-list><nav><a href="#a">A</a></nav>'
    expect(lintMockupHtml(html).filter((f) => f.rule === 'handrolled-nav')).toEqual([])
  })
})
