import { describe, expect, it } from 'vitest'
import {
  ensureNonEmptyString,
  ensureOptionalBoolean,
  ensureOptionalInt,
  ensureOptionalString,
  ensureOptionalStringArray,
  ensureRating,
  ensureStringArray,
  validateParams,
} from './validation'

const makeLongString = (length: number) => 'a'.repeat(length)

describe('validation utilities', () => {
  it('ensureNonEmptyString throws on empty or whitespace', () => {
    expect(() => ensureNonEmptyString('', 'name')).toThrow()
    expect(() => ensureNonEmptyString('   ', 'name')).toThrow()
  })

  it('ensureNonEmptyString throws on overly long strings', () => {
    expect(() => ensureNonEmptyString(makeLongString(10001), 'name')).toThrow()
  })

  it('ensureOptionalString ignores undefined and validates when set', () => {
    expect(() => ensureOptionalString(undefined, 'opt')).not.toThrow()
    expect(() => ensureOptionalString('', 'opt')).toThrow()
  })

  it('ensureOptionalString throws on overly long strings', () => {
    expect(() => ensureOptionalString(makeLongString(10001), 'opt')).toThrow()
  })

  it('ensureOptionalInt validates integer', () => {
    expect(() => ensureOptionalInt(undefined, 'limit')).not.toThrow()
    expect(() => ensureOptionalInt(1.2, 'limit')).toThrow()
  })

  it('ensureOptionalBoolean validates boolean', () => {
    expect(() => ensureOptionalBoolean(undefined, 'flag')).not.toThrow()
    expect(() => ensureOptionalBoolean('yes', 'flag')).toThrow()
  })

  it('ensureStringArray enforces size and content', () => {
    expect(() => ensureStringArray([], 'items')).toThrow()
    expect(() => ensureStringArray([''], 'items')).toThrow()
    expect(() =>
      ensureStringArray(
        Array.from({ length: 1001 }, () => 'a'),
        'items',
      ),
    ).toThrow()
    expect(() => ensureStringArray(['ok'], 'items')).not.toThrow()
  })

  it('ensureOptionalStringArray ignores undefined', () => {
    expect(() => ensureOptionalStringArray(undefined, 'tags')).not.toThrow()
  })

  it('ensureOptionalStringArray validates when set', () => {
    expect(() => ensureOptionalStringArray(['valid'], 'tags')).not.toThrow()
    expect(() => ensureOptionalStringArray([], 'tags')).toThrow()
    expect(() => ensureOptionalStringArray([''], 'tags')).toThrow()
  })

  it('ensureRating validates allowed values', () => {
    expect(() => ensureRating(undefined)).not.toThrow()
    expect(() => ensureRating('like')).not.toThrow()
    expect(() => ensureRating('bad')).toThrow()
  })

  it('validateParams enforces generic rules', () => {
    expect(() => validateParams({ user: 123 })).toThrow()
    expect(() => validateParams({ rating: 'bad' })).toThrow()
    expect(() => validateParams({ page: 1.1 })).toThrow()
    expect(() => validateParams({ files: 'bad' })).toThrow()
    expect(() => validateParams({ keyword: '' })).not.toThrow()
    expect(() => validateParams({ name: makeLongString(10001) })).toThrow()
    expect(() => validateParams({ items: Array.from({ length: 1001 }, () => 'a') })).toThrow()
    expect(() =>
      validateParams({
        data: Object.fromEntries(Array.from({ length: 101 }, (_, i) => [String(i), i])),
      }),
    ).toThrow()
    expect(() => validateParams({ user: 'u', page: 1 })).not.toThrow()
  })
})
