import { describe, it, expect } from 'vitest'
import {
  parseLocaleNumber,
  normalizeProcessName,
  normalizePosition,
  normalizeCurrency,
  isBlank,
  isNotApplicableValue,
  NOT_APPLICABLE_MARKERS,
} from '../normalizer'

describe('parseLocaleNumber', () => {
  it('returns numbers unchanged', () => {
    expect(parseLocaleNumber(42)).toBe(42)
    expect(parseLocaleNumber(0)).toBe(0)
    expect(parseLocaleNumber(-3.5)).toBe(-3.5)
  })

  it('distinguishes empty (null) from real zero', () => {
    expect(parseLocaleNumber('')).toBeNull()
    expect(parseLocaleNumber(null)).toBeNull()
    expect(parseLocaleNumber(undefined)).toBeNull()
    expect(parseLocaleNumber('   ')).toBeNull()
    expect(parseLocaleNumber('0')).toBe(0)
    expect(parseLocaleNumber(0)).toBe(0)
  })

  it('parses German number format (1.234,56)', () => {
    expect(parseLocaleNumber('1.234,56')).toBeCloseTo(1234.56, 5)
    expect(parseLocaleNumber('1.000')).toBe(1000)
    expect(parseLocaleNumber('0,5')).toBeCloseTo(0.5, 5)
  })

  it('parses English number format (1,234.56)', () => {
    expect(parseLocaleNumber('1,234.56')).toBeCloseTo(1234.56, 5)
    expect(parseLocaleNumber('1,000')).toBe(1000)
    expect(parseLocaleNumber('0.5')).toBeCloseTo(0.5, 5)
  })

  it('strips percent signs and currency symbols', () => {
    expect(parseLocaleNumber('12,5 %')).toBeCloseTo(12.5, 5)
    expect(parseLocaleNumber('1.234,56 €')).toBeCloseTo(1234.56, 5)
    expect(parseLocaleNumber('€ 1,234.56')).toBeCloseTo(1234.56, 5)
  })

  it('returns null for non-numeric text', () => {
    expect(parseLocaleNumber('Assembly')).toBeNull() // allow-customer-string
    expect(parseLocaleNumber('n/a')).toBeNull()
  })

  it('keeps a leading minus', () => {
    expect(parseLocaleNumber('-1.234,56')).toBeCloseTo(-1234.56, 5)
  })
})

describe('normalizeProcessName', () => {
  it('lowercases, collapses whitespace, trims', () => {
    expect(normalizeProcessName('  Spritz   Guss ')).toBe('spritz guss')
  })

  it('treats diacritics consistently', () => {
    expect(normalizeProcessName('Löten')).toBe(normalizeProcessName('Loeten'))
  })

  it('returns empty string for blank input', () => {
    expect(normalizeProcessName('')).toBe('')
    expect(normalizeProcessName('   ')).toBe('')
  })
})

describe('normalizePosition', () => {
  it('keeps alphanumeric position as text (2a stays 2a)', () => {
    expect(normalizePosition('2a')).toBe('2a')
    expect(normalizePosition(' 10 ')).toBe('10')
  })

  it('does not coerce to number or drop leading zeros', () => {
    expect(normalizePosition('007')).toBe('007')
  })
})

describe('normalizeCurrency', () => {
  it('uppercases and trims', () => {
    expect(normalizeCurrency(' eur ')).toBe('EUR')
  })

  it('returns null for blank', () => {
    expect(normalizeCurrency('')).toBeNull()
    expect(normalizeCurrency('   ')).toBeNull()
  })
})

describe('isBlank', () => {
  it('treats null/undefined/empty as blank but not zero', () => {
    expect(isBlank(null)).toBe(true)
    expect(isBlank(undefined)).toBe(true)
    expect(isBlank('')).toBe(true)
    expect(isBlank('  ')).toBe(true)
    expect(isBlank(0)).toBe(false)
    expect(isBlank('0')).toBe(false)
  })
})

// P0.6 / KAR-891: "n.a." must be distinguishable from a genuinely empty cell —
// parseLocaleNumber alone collapses both to null, so this is a separate detector.
describe('isNotApplicableValue', () => {
  it('recognizes known DE/EN not-applicable markers (case-insensitive, trimmed)', () => {
    expect(isNotApplicableValue('n.a.')).toBe(true)
    expect(isNotApplicableValue('N.A.')).toBe(true)
    expect(isNotApplicableValue(' n/a ')).toBe(true)
    expect(isNotApplicableValue('entfällt')).toBe(true)
    expect(isNotApplicableValue('Entfaellt')).toBe(true)
    expect(isNotApplicableValue('not applicable')).toBe(true)
    expect(isNotApplicableValue('Nicht anwendbar')).toBe(true)
    expect(isNotApplicableValue('-')).toBe(true)
  })

  it('does not treat a genuinely empty cell as not-applicable', () => {
    expect(isNotApplicableValue('')).toBe(false)
    expect(isNotApplicableValue('   ')).toBe(false)
    expect(isNotApplicableValue(null)).toBe(false)
    expect(isNotApplicableValue(undefined)).toBe(false)
  })

  it('does not treat arbitrary text or real numbers as not-applicable (conservative)', () => {
    expect(isNotApplicableValue('Assembly')).toBe(false) // allow-customer-string
    expect(isNotApplicableValue('Spritzguss')).toBe(false)
    expect(isNotApplicableValue(0)).toBe(false)
    expect(isNotApplicableValue('0')).toBe(false)
    expect(isNotApplicableValue(42)).toBe(false)
  })

  it('exposes the vocabulary as a stable, non-empty constant', () => {
    expect(NOT_APPLICABLE_MARKERS.length).toBeGreaterThan(0)
    expect(NOT_APPLICABLE_MARKERS).toContain('n.a.')
  })
})
