import { describe, expect, it } from 'vitest'
import {
  assertExactStorageKey,
  assertPresignExpiry,
  isStorageError,
  StorageError,
  type StorageErrorCode,
} from './storage'

describe('@platform-modules/uploads/storage', () => {
  describe('isStorageError', () => {
    it('returns true for a StorageError instance', () => {
      expect(isStorageError(new StorageError('backend', 'x'))).toBe(true)
    })

    it('returns true for a plain structural object', () => {
      expect(isStorageError({ isStorageError: true, code: 'backend', message: 'x' })).toBe(true)
    })

    it('returns false for non-storage errors and non-objects', () => {
      expect(isStorageError(new Error('x'))).toBe(false)
      expect(isStorageError(null)).toBe(false)
      expect(isStorageError(undefined)).toBe(false)
      expect(isStorageError({})).toBe(false)
      expect(isStorageError('x')).toBe(false)
    })
  })

  describe('StorageError', () => {
    const codes: StorageErrorCode[] = ['invalid_key', 'not_found', 'backend']

    it.each(codes)('carries code, message, name, and structural flag for %s', (code) => {
      const err = new StorageError(code, 'test message')
      expect(err.code).toBe(code)
      expect(err.message).toBe('test message')
      expect(err.name).toBe('StorageError')
      expect(err.isStorageError).toBe(true)
    })
  })

  describe('assertExactStorageKey', () => {
    it.each(['', 'a/*', 'a?b', 'a/'])('throws invalid_key for %j', (key) => {
      expect(() => assertExactStorageKey(key)).toThrow(StorageError)
      try {
        assertExactStorageKey(key)
      } catch (e) {
        expect(isStorageError(e)).toBe(true)
        expect((e as StorageError).code).toBe('invalid_key')
      }
    })

    it('does not throw for a normal exact key', () => {
      expect(() => assertExactStorageKey('media/2026/06/x.png')).not.toThrow()
    })
  })

  describe('assertPresignExpiry', () => {
    it.each([0, -1, NaN, Infinity])('throws RangeError for %s', (expiresIn) => {
      expect(() => assertPresignExpiry(expiresIn)).toThrow(RangeError)
    })

    it('does not throw for a positive finite expiry', () => {
      expect(() => assertPresignExpiry(60)).not.toThrow()
    })
  })
})
