import fs from 'node:fs'
import path from 'node:path'
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import MenuList from '../src/components/MenuList/MenuList.vue'

// P1-4 (owner 2026-07-24): per-item `badge` field — code-first additive.
// Shorthand string|number → red Circle badge (alert count); object → canonical Badge props.
// Reuses canonical Badge (color/fill/type + slot content). icon? already supported.
describe('MenuList per-item badge (P1-4, code-first additive)', () => {
  it('renders no badge element when an item has no badge field', () => {
    const w = mount(MenuList, { props: { items: [{ label: 'Home' }] } })
    expect(w.find('.canonical-badge').exists()).toBe(false)
  })

  it('shorthand number → red Circle badge carrying the value as content', () => {
    const w = mount(MenuList, { props: { items: [{ label: 'Alerts', badge: 3 }] } })
    const badge = w.find('.canonical-badge')
    expect(badge.exists()).toBe(true)
    expect(badge.text()).toBe('3')
    expect(badge.attributes('data-figma-color')).toBe('Red')
    expect(badge.attributes('data-figma-type')).toBe('Circle')
  })

  it('shorthand number 0 still renders (0 is a real count, not "absent")', () => {
    const w = mount(MenuList, { props: { items: [{ label: 'Queue', badge: 0 }] } })
    const badge = w.find('.canonical-badge')
    expect(badge.exists()).toBe(true)
    expect(badge.text()).toBe('0')
  })

  it('shorthand string → renders its text (e.g. "99+")', () => {
    const w = mount(MenuList, { props: { items: [{ label: 'Inbox', badge: '99+' }] } })
    expect(w.find('.canonical-badge').text()).toBe('99+')
  })

  it('object badge maps color / fill / type and label content', () => {
    const w = mount(MenuList, {
      props: { items: [{ label: 'Live', badge: { label: 'NEW', color: 'Green', fill: 'Line', type: 'Rectangle' } }] },
    })
    const badge = w.find('.canonical-badge')
    expect(badge.text()).toBe('NEW')
    expect(badge.attributes('data-figma-color')).toBe('Green')
    expect(badge.attributes('data-figma-tag')).toBe('Line') // canonical Badge maps `fill` → data-figma-tag
    expect(badge.attributes('data-figma-type')).toBe('Rectangle')
  })

  it('object badge without explicit color defaults to Red (alert-centric)', () => {
    const w = mount(MenuList, { props: { items: [{ label: 'Warn', badge: { label: '!' } }] } })
    expect(w.find('.canonical-badge').attributes('data-figma-color')).toBe('Red')
  })

  it('keeps the existing leading icon alongside a badge', () => {
    const w = mount(MenuList, { props: { items: [{ label: 'Alerts', icon: 'action/add', badge: 1 }] } })
    expect(w.find('.menu-list__icon').exists()).toBe(true)
    expect(w.find('.canonical-badge').exists()).toBe(true)
  })
})

// horizontal active follows Figma (owner ruling "path B", 2026-08-14)
//
// Why this is a source-regex test and not a computed-style one: the styles are SFC-scoped
// CSS, which jsdom never applies, so `getComputedStyle` in a mounted wrapper reports
// nothing either way — it would pass whatever the CSS said. Same posture as
// tests/FigmaFirstContract.test.ts. What it pins: the horizontal orientation is a stand-in
// for the Menu sub-component inside the published Figma `Top bar` (`4771:7173`), where
// active `4771:7142` and normal `4771:7140` differ ONLY in text colour and every instance
// under the Menu slot has `strokes: []`. A brand underline was invented in code on
// 2026-07-02 and surfaced on the Sync A card; this test is what stops it coming back.
describe('MenuList horizontal — active state follows Figma Top bar Menu', () => {
  const source = fs.readFileSync(
    path.join(__dirname, '../src/components/MenuList/MenuList.vue'),
    'utf8',
  )
  const block = (marker: string) => {
    const start = source.indexOf(`/* ---- ${marker}`)
    const end = source.indexOf('/* ---- shared states ----')
    expect(start, `style block "${marker}" not found — did the section comments change?`)
      .toBeGreaterThan(-1)
    expect(end).toBeGreaterThan(start)
    return source.slice(start, end)
  }
  const horizontal = block('horizontal (topbar nav)')

  // Anti-vacuous guard: if the slice were empty or mis-anchored every assertion below
  // would pass by accident, so prove the block is real and is the one we think it is.
  it('extracts a non-empty horizontal block that is not the vertical one', () => {
    expect(horizontal.length).toBeGreaterThan(200)
    expect(horizontal).toContain('.menu-list--horizontal .menu-list__item.is-active')
    expect(horizontal).not.toContain('.menu-list--vertical')
  })

  it('paints the active item with text colour only — no underline anywhere in the block', () => {
    expect(horizontal).not.toMatch(/border-bottom/)
    expect(horizontal).toMatch(
      /\.menu-list--horizontal \.menu-list__item\.is-active\s*\{[^}]*color:\s*var\(--text-body\)/,
    )
    // …and specifically NOT the pre-2026-08-14 brand treatment.
    expect(horizontal).not.toMatch(/is-active\s*\{[^}]*var\(--brand\)/)
  })

  it('uses the Figma type / colour / spacing tokens for the item and the row', () => {
    expect(horizontal).toMatch(/font:\s*var\(--text-style-headline-2\)/)
    expect(horizontal).toMatch(/color:\s*var\(--text-tips\)/)
    expect(horizontal).toMatch(/padding:\s*0 var\(--sp-xs\)/)
    expect(horizontal).toMatch(/\.menu-list--horizontal\s*\{[^}]*gap:\s*var\(--sp-m\)/)
  })

  // Negative control for the whole idea: the VERTICAL orientation is code-first with no
  // Figma counterpart, so it legitimately keeps --brand. If this ever fails together with
  // the assertions above, someone ran a blanket find-and-replace instead of a scoped fix.
  it('leaves the vertical orientation on --brand (code-first, out of scope)', () => {
    expect(block('vertical (dropdown / panel body)')).toMatch(
      /\.menu-list--vertical \.menu-list__item\.is-active\s*\{[^}]*color:\s*var\(--brand\)/,
    )
  })
})
