import { BlobPermission } from './blob-permission.js'

describe('BlobPermission', () => {
  describe('static', () => {
    describe('fromString', () => {
      it('should parse positional scope', () => {
        const scope = BlobPermission.fromString('blob:image/png')
        expect(scope).not.toBeNull()
        expect(scope!.accept).toEqual(['image/png'])
      })

      it('should parse valid blob scope with multiple accept parameters', () => {
        const scope = BlobPermission.fromString(
          'blob?accept=image/png&accept=image/jpeg',
        )
        expect(scope).not.toBeNull()
        expect(scope!.accept).toEqual(['image/png', 'image/jpeg'])
      })

      it('should reject blob scope without accept', () => {
        const scope = BlobPermission.fromString('blob')
        expect(scope).toBeNull()
      })

      for (const invalid of [
        'invalid',
        'scope',
        'blob:invalid',
        'blob?accept=invalid-mime',
        'blob?accept=invalid',
        'blob:*/**',
        'blob:*/png',
      ]) {
        it(`should return null for invalid rpc scope: ${invalid}`, () => {
          expect(BlobPermission.fromString(invalid)).toBeNull()
        })
      }
    })

    describe('scopeNeededFor', () => {
      it('should return correct scope string for specific MIME type', () => {
        const scope = BlobPermission.scopeNeededFor({ mime: 'image/png' })
        expect(scope).toBe('blob:image/png')
      })

      it('should return scope that accepts all MIME types', () => {
        const scope = BlobPermission.scopeNeededFor({
          mime: 'application/json',
        })
        expect(scope).toBe('blob:application/json')
      })
    })
  })

  describe('instance', () => {
    describe('matches', () => {
      it('should match exact MIME type', () => {
        const scope = BlobPermission.fromString('blob:image/png')
        expect(scope).not.toBeNull()
        expect(scope!.matches({ mime: 'image/png' })).toBe(true)
      })

      it('should match wildcard MIME type', () => {
        const scope = BlobPermission.fromString('blob:*/*')
        expect(scope).not.toBeNull()
        expect(scope!.matches({ mime: 'image/jpeg' })).toBe(true)
        expect(scope!.matches({ mime: 'application/json' })).toBe(true)
      })

      it('should match subtype wildcard MIME type', () => {
        const scope = BlobPermission.fromString('blob:image/*')
        expect(scope).not.toBeNull()
        expect(scope!.matches({ mime: 'image/gif' })).toBe(true)
      })

      it('should not match different MIME type', () => {
        const scope = BlobPermission.fromString('blob:image/png')
        expect(scope).not.toBeNull()
        expect(scope!.matches({ mime: 'image/jpeg' })).toBe(false)
      })

      it('should match multiple accept values', () => {
        const scope = BlobPermission.fromString(
          'blob?accept=image/png&accept=image/jpeg',
        )
        expect(scope).not.toBeNull()
        expect(scope!.matches({ mime: 'image/png' })).toBe(true)
        expect(scope!.matches({ mime: 'image/jpeg' })).toBe(true)
        expect(scope!.matches({ mime: 'image/gif' })).toBe(false)
      })
    })

    describe('toString', () => {
      it('should format scope with accept parameter', () => {
        const scope = new BlobPermission(['image/png', 'image/jpeg'])
        expect(scope.toString()).toBe('blob?accept=image/jpeg&accept=image/png')
      })

      it('should strip redundant accept parameters', () => {
        expect(new BlobPermission(['*/*', 'image/*']).toString()).toBe(
          'blob:*/*',
        )
        expect(new BlobPermission(['*/*', 'image/png']).toString()).toBe(
          'blob:*/*',
        )
        expect(new BlobPermission(['image/*', 'image/png']).toString()).toBe(
          'blob:image/*',
        )
      })

      it('should use positional format for single accept', () => {
        expect(new BlobPermission(['image/png']).toString()).toBe(
          'blob:image/png',
        )
        expect(new BlobPermission(['image/*']).toString()).toBe('blob:image/*')
        expect(new BlobPermission(['*/*']).toString()).toBe('blob:*/*')
      })

      it('should use query format for multiple accepts', () => {
        expect(new BlobPermission(['image/png', 'image/jpeg']).toString()).toBe(
          'blob?accept=image/jpeg&accept=image/png',
        )
      })
    })
  })
})
