import { describe, expect, it } from 'vitest'
import {
  PublicDomainError,
  ownerScopedNotFound,
  publicErrors,
  toOwnedConversionDto,
  type ConversionRecord,
} from '../src/index.js'

const record: ConversionRecord = {
  id: 'conversion-1',
  ownerId: 'owner-1',
  sourceFilename: 'document.pdf',
  status: 'Complete',
  acceptedAt: new Date('2026-01-01T00:00:00.000Z'),
  sourceExpiresAt: new Date('2026-01-03T00:00:00.000Z'),
  completedAt: new Date('2026-01-01T01:00:00.000Z'),
  zipExpiresAt: new Date('2026-01-03T01:00:00.000Z'),
  failureCode: null,
  publicFailureMessage: null,
  sourceStorageKey: 'private/source/object-key',
  zipStorageKey: 'private/output/object-key',
  debitLedgerEntryId: 'ledger-private-1',
  compensationLedgerEntryId: null,
}

describe('typed errors and ownership-safe DTOs', () => {
  it('serializes only the closed public error shape', () => {
    expect(publicErrors.outOfCredits()).toBeInstanceOf(PublicDomainError)
    expect(publicErrors.outOfCredits().toJSON()).toEqual({
      code: 'OUT_OF_CREDITS',
      message: "You're out of credits.",
      retryable: false,
    })
    expect(ownerScopedNotFound().code).toBe('NOT_FOUND')
  })

  it('projects only customer-safe fields after ownership validation', () => {
    const dto = toOwnedConversionDto(record, 'owner-1', new Date('2026-01-02T00:00:00.000Z'))
    expect(dto.canDownload).toBe(true)
    const serialized = JSON.stringify(dto)
    expect(serialized).not.toContain('owner-1')
    expect(serialized).not.toContain('object-key')
    expect(serialized).not.toContain('ledger-private')
  })

  it('uses the same non-enumerating not-found error for a wrong owner', () => {
    expect(() => toOwnedConversionDto(record, 'different-owner')).toThrowError(
      expect.objectContaining({ code: 'NOT_FOUND', status: 404 }),
    )
  })

  it('projects an expired completed artifact without exposing a download', () => {
    const dto = toOwnedConversionDto(record, 'owner-1', record.zipExpiresAt!)
    expect(dto.status).toBe('Expired')
    expect(dto.canDownload).toBe(false)
  })
})
