// Page order is the one thing here that costs money to get wrong: a run of
// badge cards with the backs one card out looks perfect until someone reads
// one. These tests pin the order and the CSV contract.

import { describe, it, expect } from 'vitest'

import { parseCsv, splitCsvLine, buildPages, MAX_LABELS } from './labelPages'

const sides = pages => pages.map(page => page.side).join(' ')
const contents = pages => pages.map(page => page.content || '-').join(' ')

describe('splitCsvLine', () => {
  it('keeps a comma that is inside quotes', () => {
    expect(splitCsvLine('WJ-0001,"Bay 12, press",2')).toEqual(['WJ-0001', 'Bay 12, press', '2'])
  })

  it('unescapes a doubled quote', () => {
    expect(splitCsvLine('x,"the ""big"" one"')).toEqual(['x', 'the "big" one'])
  })
})

describe('parseCsv', () => {
  it('reads a named header in any column order', () => {
    const rows = parseCsv('copies,label,content\n3,Line 1,WJ-0001')
    expect(rows).toEqual([
      { content: 'WJ-0001', label: 'Line 1', copies: 3, back: '', backlabel: '' },
    ])
  })

  it('falls back to positional columns with no header', () => {
    const rows = parseCsv('WJ-0001,Line 1,2,WJ-0001-B,Reverse')
    expect(rows[0]).toEqual({
      content: 'WJ-0001', label: 'Line 1', copies: 2,
      back: 'WJ-0001-B', backlabel: 'Reverse',
    })
  })

  it('skips a row with no content rather than printing a blank sticker', () => {
    expect(parseCsv('content,label\n,orphan\nWJ-0002,real')).toHaveLength(1)
  })

  it('defaults copies to 1 when it is missing or junk', () => {
    expect(parseCsv('content,copies\nA,\nB,zero')[0].copies).toBe(1)
    expect(parseCsv('content,copies\nA,\nB,zero')[1].copies).toBe(1)
  })
})

describe('buildPages without a back side', () => {
  it('expands copies and emits fronts only', () => {
    const { pages, backs } = buildPages([{ content: 'A', label: 'a', copies: 3 }])
    expect(sides(pages)).toBe('front front front')
    expect(backs).toHaveLength(0)
  })

  it('caps cards, not pages, and says how many it dropped', () => {
    const { fronts, dropped } = buildPages([{ content: 'A', copies: MAX_LABELS + 5 }])
    expect(fronts).toHaveLength(MAX_LABELS)
    expect(dropped).toBe(5)
  })
})

describe('buildPages with a back side', () => {
  const rows = [
    { content: 'A', label: 'a', copies: 2, back: 'A2', backlabel: 'a2' },
    { content: 'B', label: 'b', copies: 1, back: 'B2', backlabel: 'b2' },
  ]

  it('interleaves front and back, which is what a duplex driver takes', () => {
    const { pages } = buildPages(rows, { back: { enabled: true, source: 'column', order: 'interleave' } })
    expect(sides(pages)).toBe('front back front back front back')
    expect(contents(pages)).toBe('A A2 A A2 B B2')
  })

  it('groups every front then every back, for a flip-and-reload printer', () => {
    const { pages } = buildPages(rows, { back: { enabled: true, source: 'column', order: 'grouped' } })
    expect(sides(pages)).toBe('front front front back back back')
    // Same card order in both halves, or the flipped stack pairs up wrong.
    expect(contents(pages)).toBe('A A B A2 A2 B2')
  })

  it('still emits a back for a row that left the back column empty', () => {
    const { pages } = buildPages(
      [{ content: 'A', copies: 1 }, { content: 'B', copies: 1, back: 'B2' }],
      { back: { enabled: true, source: 'column', order: 'interleave' } })
    // A page count that changes per row would shift every later back onto the
    // wrong front.
    expect(sides(pages)).toBe('front back front back')
    expect(contents(pages)).toBe('A - B B2')
  })

  it('repeats the front payload when the back is the same code', () => {
    const { backs } = buildPages(rows, { back: { enabled: true, source: 'code' } })
    expect(contents(backs)).toBe('A A B')
  })

  it('puts the same fixed text on every back and no code', () => {
    const { backs } = buildPages(rows, { back: { enabled: true, source: 'text', text: 'Property of GE' } })
    expect(backs.every(page => page.content === '')).toBe(true)
    expect(backs.every(page => page.label === 'Property of GE')).toBe(true)
  })

  it('leaves a blank back entirely empty but still counted', () => {
    const { pages, backs } = buildPages(rows, { back: { enabled: true, source: 'blank' } })
    expect(pages).toHaveLength(6)
    expect(backs.every(page => !page.content && !page.label)).toBe(true)
  })

  it('falls back to the fixed text when a row has no back label', () => {
    const { backs } = buildPages([{ content: 'A', copies: 1, back: 'A2' }],
      { back: { enabled: true, source: 'column', text: 'Return to IT' } })
    expect(backs[0].label).toBe('Return to IT')
  })
})
