import { describe, expect, it } from 'vitest'
import { MAX_BODY_LEN, normalizeCommentInput } from './model.js'
import { CommentValidationError } from './errors.js'

const target = { type: 'post', id: 'p1' }
const userAuthor = { kind: 'user' as const, userId: 'u1' }
const guestAuthor = { kind: 'guest' as const, name: 'Alice' }

describe('normalizeCommentInput', () => {
  it('passes a valid user comment', () => {
    const result = normalizeCommentInput({ target, author: userAuthor, body: 'Hello world' })
    expect(result.body).toBe('Hello world')
    expect(result.target).toEqual(target)
    expect(result.author).toEqual(userAuthor)
  })

  it('passes a valid guest comment', () => {
    const result = normalizeCommentInput({ target, author: guestAuthor, body: 'hi' })
    expect(result.author).toEqual(guestAuthor)
  })

  it('throws on empty body', () => {
    expect(() => normalizeCommentInput({ target, author: userAuthor, body: '' })).toThrow(CommentValidationError)
    expect(() => normalizeCommentInput({ target, author: userAuthor, body: '   ' })).toThrow(CommentValidationError)
  })

  it('throws on body exceeding MAX_BODY_LEN', () => {
    const longBody = 'x'.repeat(MAX_BODY_LEN + 1)
    const err = (() => {
      try {
        normalizeCommentInput({ target, author: userAuthor, body: longBody })
      } catch (e) {
        return e
      }
    })()
    expect(err).toBeInstanceOf(CommentValidationError)
    expect((err as CommentValidationError).field).toBe('body')
  })

  it('accepts body exactly at MAX_BODY_LEN', () => {
    const body = 'x'.repeat(MAX_BODY_LEN)
    expect(() => normalizeCommentInput({ target, author: userAuthor, body })).not.toThrow()
  })

  it('throws on missing target type', () => {
    expect(() =>
      normalizeCommentInput({ target: { type: '', id: 'p1' }, author: userAuthor, body: 'ok' }),
    ).toThrow(CommentValidationError)
  })

  it('throws on missing target id', () => {
    expect(() =>
      normalizeCommentInput({ target: { type: 'post', id: '' }, author: userAuthor, body: 'ok' }),
    ).toThrow(CommentValidationError)
  })

  it('throws on guest without name', () => {
    expect(() =>
      normalizeCommentInput({
        target,
        author: { kind: 'guest', name: '' } as ReturnType<typeof Object>,
        body: 'hi',
      }),
    ).toThrow(CommentValidationError)
  })

  it('throws on user without userId', () => {
    expect(() =>
      normalizeCommentInput({
        target,
        author: { kind: 'user', userId: '' } as ReturnType<typeof Object>,
        body: 'hi',
      }),
    ).toThrow(CommentValidationError)
  })

  it('throws on unknown author kind', () => {
    expect(() =>
      normalizeCommentInput({
        target,
        author: { kind: 'org', name: 'ACME' } as ReturnType<typeof Object>,
        body: 'hi',
      }),
    ).toThrow(CommentValidationError)
  })
})
