// Namensnormalisierung für den Material-Abgleich (Kap. 8.3).

import { describe, it, expect } from 'vitest'
import { normalizeMaterialName, namesMatch, tokenOverlap } from '../material-name'

describe('normalizeMaterialName', () => {
  it('vereinheitlicht Schreibweise, Leerzeichen und Rand', () => {
    expect(normalizeMaterialName('  Bracket   Module  Side ').normalized).toBe('bracket module side')
    expect(normalizeMaterialName('BRACKET MODULE SIDE').normalized).toBe('bracket module side')
  })

  it('kanonisiert typografische Varianten', () => {
    // Dieselbe Position, getippt von zwei verschiedenen Leuten.
    expect(namesMatch('Sensor – links', 'Sensor - links')).toBe(true)
    expect(namesMatch('Leitung → Motor', 'Leitung - Motor')).toBe(true)
    expect(namesMatch('Halter oben', 'Halter oben')).toBe(true)
  })

  it('trennt ein Mengenpräfix ab, ohne es zu verlieren', () => {
    const n = normalizeMaterialName('3 x Schraube')
    expect(n.quantityPrefix).toBe(3)
    expect(n.normalized).toBe('screw')
    // Gleiche Position, andere Menge — nicht zwei verschiedene Positionen.
    expect(n.normalized).toBe(normalizeMaterialName('Schraube').normalized)
  })

  it('behandelt Mengenpräfixe mit ungewöhnlichen Abständen', () => {
    expect(normalizeMaterialName('12  X   Niet').quantityPrefix).toBe(12)
  })

  it('erhält Klammerinhalte als Unterscheidungsmerkmal', () => {
    // „links" und „rechts" sind zwei echte Positionen; sie zu verschmelzen
    // fiele erst in der Summe auf und wäre dann kaum zu finden.
    expect(namesMatch('Halter (links)', 'Halter (rechts)')).toBe(false)
    expect(normalizeMaterialName('Halter (links)').normalized).toContain('links')
  })

  it('führt kuratierte Synonyme zusammen', () => {
    expect(namesMatch('Steuergerät', 'Control Unit')).toBe(true)
    expect(namesMatch('ECU', 'control unit')).toBe(true)
    expect(namesMatch('Halterung', 'Bracket')).toBe(true)
  })

  it('lässt Füllwörter aus den Tokens heraus', () => {
    const n = normalizeMaterialName('Halter für die Leitung')
    expect(n.tokens).not.toContain('für')
    expect(n.tokens).not.toContain('die')
    expect(n.tokens).toContain('bracket')
  })

  it('macht aus leeren Eingaben keine Treffer', () => {
    // Zwei namenlose Positionen sind nicht „dieselbe" Position.
    expect(normalizeMaterialName(null).normalized).toBe('')
    expect(normalizeMaterialName('   ').normalized).toBe('')
    expect(namesMatch('', '')).toBe(false)
    expect(namesMatch(null, null)).toBe(false)
  })

  it('unterscheidet Positionen, die sich nur in einer Ziffer unterscheiden', () => {
    expect(namesMatch('Sensor 1', 'Sensor 2')).toBe(false)
  })
})

describe('tokenOverlap — nur Kandidatenfilter, nie Entscheidung', () => {
  it('misst den Anteil gemeinsamer Tokens', () => {
    const a = normalizeMaterialName('Bracket Module Side')
    const b = normalizeMaterialName('Bracket Module')
    expect(tokenOverlap(a, b)).toBeCloseTo(2 / 3, 6)
  })

  it('ist 0 ohne gemeinsame Tokens und ohne Tokens', () => {
    expect(tokenOverlap(normalizeMaterialName('Sensor'), normalizeMaterialName('Dichtung'))).toBe(0)
    expect(tokenOverlap(normalizeMaterialName(''), normalizeMaterialName('Sensor'))).toBe(0)
  })

  it('ist 1 bei gleicher Tokenmenge', () => {
    expect(tokenOverlap(normalizeMaterialName('Sensor links'), normalizeMaterialName('links Sensor'))).toBe(1)
  })
})
