import { describe, it, expect } from 'vitest'
import { buildMovers, topMovers, type MoverRow } from '../movers'

describe('buildMovers', () => {
  const stepDiffs = [
    { stepLabel: '2 Schweissen', delta: 300, uncertain: false },
    { stepLabel: '1 Montage', delta: -30, uncertain: true },
    { stepLabel: '3 Pruefen', delta: 40, uncertain: false },
    { stepLabel: '4 Kleben', delta: null, uncertain: false },
    { stepLabel: '5 Ruhen', delta: 0, uncertain: false },
  ]

  it('ranks process-step deltas by absolute magnitude (V11 movers)', () => {
    const movers = buildMovers({ rows: stepDiffs })
    expect(movers.kind).toBe('prozessschritt')
    expect(movers.rows.map((r) => r.label)).toEqual(['2 Schweissen', '3 Pruefen', '1 Montage'])
    expect(movers.rows[0].delta).toBe(300)
  })

  it('carries the uncertain-match flag per row', () => {
    const movers = buildMovers({ rows: stepDiffs })
    expect(movers.rows.find((r) => r.label === '1 Montage')!.uncertain).toBe(true)
    expect(movers.rows.find((r) => r.label === '2 Schweissen')!.uncertain).toBe(false)
  })

  it('drops null and zero deltas (no visual noise)', () => {
    const movers = buildMovers({ rows: stepDiffs })
    expect(movers.rows.some((r) => r.label === '4 Kleben' || r.label === '5 Ruhen')).toBe(false)
  })

  it('disambiguates duplicate labels so bars stay distinguishable', () => {
    const movers = buildMovers({
      rows: [
        { stepLabel: '—', delta: 5, uncertain: false },
        { stepLabel: '—', delta: 3, uncertain: false },
      ],
    })
    expect(movers.rows.map((r) => r.label)).toEqual(['—', '— (2)'])
  })

  it('falls back to the comparison-object row when no step deltas exist (summary QAFs)', () => {
    const movers = buildMovers({ rows: [], fallback: { label: 'Streulichtblende G5x', delta: 1.23 } })
    expect(movers.kind).toBe('vergleichsobjekt')
    expect(movers.rows).toEqual([{ label: 'Streulichtblende G5x', delta: 1.23, uncertain: false }])
  })

  it('does not fall back when steps existed but all netted to zero', () => {
    const movers = buildMovers({
      rows: [{ stepLabel: '1 Montage', delta: 0, uncertain: false }],
      fallback: { label: 'X', delta: 1.23 },
    })
    expect(movers.kind).toBe('prozessschritt')
    expect(movers.rows).toEqual([])
  })

  it('drops a zero fallback delta (no phantom bar)', () => {
    const movers = buildMovers({ rows: [], fallback: { label: 'X', delta: 0 } })
    expect(movers.rows).toEqual([])
  })

  it('returns an empty set when there is neither step data nor a fallback delta', () => {
    const movers = buildMovers({ rows: [], fallback: { label: 'X', delta: null } })
    expect(movers.rows).toEqual([])
  })
})

describe('topMovers', () => {
  const rows: MoverRow[] = Array.from({ length: 30 }, (_, i) => ({ label: `s${i}`, delta: 30 - i, uncertain: false }))

  it('caps at the requested top-N', () => {
    expect(topMovers(rows, 5)).toHaveLength(5)
    expect(topMovers(rows, 12)).toHaveLength(12)
  })

  it("returns everything for 'all'", () => {
    expect(topMovers(rows, 'all')).toHaveLength(30)
  })
})
