import { describe, expect, it } from 'vitest'
import { parseAnsiScreen } from './ansi-screen'

const ESC = '\u001b'

describe('parseAnsiScreen', () => {
  it('splits plain text into one segment per line', () => {
    const lines = parseAnsiScreen('first\nsecond')
    expect(lines).toHaveLength(2)
    expect(lines[0]).toEqual([expect.objectContaining({ text: 'first', fg: null })])
  })

  it('applies foreground colour as a palette index', () => {
    const lines = parseAnsiScreen(`${ESC}[32mgreen${ESC}[0m plain`)
    expect(lines[0]![0]).toMatchObject({ text: 'green', fg: 2 })
    expect(lines[0]![1]).toMatchObject({ text: ' plain', fg: null })
  })

  it('maps bright colours into the upper half of the palette', () => {
    expect(parseAnsiScreen(`${ESC}[91mhot`)[0]![0]).toMatchObject({ fg: 9 })
    expect(parseAnsiScreen(`${ESC}[38;5;12mindexed`)[0]![0]).toMatchObject({ fg: 12 })
  })

  it('falls back to the default colour for palette entries with no token', () => {
    expect(parseAnsiScreen(`${ESC}[38;5;200mfancy`)[0]![0]).toMatchObject({ fg: null })
    expect(parseAnsiScreen(`${ESC}[38;2;10;20;30mtrue`)[0]![0]).toMatchObject({ fg: null, text: 'true' })
  })

  it('carries attributes and clears them on reset', () => {
    const lines = parseAnsiScreen(`${ESC}[1;4mloud${ESC}[22;24mquiet`)
    expect(lines[0]![0]).toMatchObject({ text: 'loud', bold: true, underline: true })
    expect(lines[0]![1]).toMatchObject({ text: 'quiet', bold: false, underline: false })
  })

  it('keeps style across a line break, as a terminal does', () => {
    const lines = parseAnsiScreen(`${ESC}[31mred\nstill red`)
    expect(lines[1]![0]).toMatchObject({ fg: 1 })
  })

  it('strips non-SGR control sequences instead of printing them', () => {
    const lines = parseAnsiScreen(`${ESC}[2J${ESC}[HclearAnd${ESC}]0;title${ESC}\\done`)
    expect(lines[0]!.map((segment) => segment.text).join('')).toBe('clearAnddone')
  })

  it('merges adjacent segments that share a style', () => {
    expect(parseAnsiScreen(`a${ESC}[39mb`)[0]).toHaveLength(1)
  })

  it('returns an empty row for an empty line', () => {
    expect(parseAnsiScreen('a\n\nb')[1]).toEqual([])
  })
})
