import { describe, expect, it } from 'vitest'
import { decodeCursor, encodeCursor } from './cursor.js'
import { InvalidCursorError } from './errors.js'

describe('cursor codec', () => {
  it('encode then decode roundtrip preserves createdAt and id', () => {
    const row = {
      createdAt: new Date('2026-06-16T12:00:00.000Z'),
      id: '550e8400-e29b-41d4-a716-446655440000',
    }

    const encoded = encodeCursor(row)
    expect(decodeCursor(encoded)).toEqual({
      createdAt: row.createdAt.toISOString(),
      id: row.id,
    })
  })

  it('decodeCursor throws InvalidCursorError on malformed base64', () => {
    expect(() => decodeCursor('!!!not-b64')).toThrow(InvalidCursorError)
  })

  it('decodeCursor throws InvalidCursorError on wrong JSON shape', () => {
    const wrongShape = btoa(JSON.stringify({ foo: 'bar' }))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '')

    expect(() => decodeCursor(wrongShape)).toThrow(InvalidCursorError)
  })

  it('decodeCursor throws InvalidCursorError on valid shape but unparseable createdAt', () => {
    const forged = btoa(JSON.stringify({ createdAt: 'garbage', id: 'x' }))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '')

    expect(() => decodeCursor(forged)).toThrow(InvalidCursorError)
  })

  it('decodeCursor throws InvalidCursorError when id is not a uuid (would hit the uuid column raw)', () => {
    const forged = btoa(
      JSON.stringify({ createdAt: '2026-06-16T12:00:00.000Z', id: 'not-a-uuid' }),
    )
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '')

    expect(() => decodeCursor(forged)).toThrow(InvalidCursorError)
  })
})
