import { describe, it, expect, vi, beforeEach } from 'vitest'
import {
  createStorageUploadTool,
  createStorageSignedUrlTool,
  createStorageDownloadTool,
  createStorageDeleteTool,
  createStorageListTool,
  StorageUploadInputSchema,
  StorageSignedUrlInputSchema,
  StorageDownloadInputSchema,
  StorageDeleteInputSchema,
  StorageListInputSchema
} from '../index'
import { ToolingError } from '../../../types'
import { getToolServices } from '../../../registry'
import { createMockExecutionContext } from '../../../../test-utils/mocks'

vi.mock('../../../registry', () => ({
  getToolServices: vi.fn()
}))

describe('Storage Platform Tools', () => {
  const mockConfig = {
    name: 'test_storage_tool',
    description: 'Test storage tool description'
  }

  const mockContext = createMockExecutionContext({
    organizationId: 'org-123',
    executionId: 'exec-456',
    resourceId: 'agent-789'
  })

  const mockStorageService = {
    upload: vi.fn(),
    download: vi.fn(),
    createSignedUrl: vi.fn(),
    delete: vi.fn(),
    list: vi.fn()
  }

  beforeEach(() => {
    vi.clearAllMocks()
    vi.mocked(getToolServices).mockReturnValue({
      commandQueueService: null,
      taskSchedulerService: null,
      notificationsService: null,
      emailService: null,
      credentialsService: null,
      integrationService: null,
      leadService: null,
      storageService: mockStorageService
    })
  })

  describe('createStorageUploadTool', () => {
    describe('tool creation', () => {
      it('creates tool with correct name and description', () => {
        const tool = createStorageUploadTool({ name: 'upload_file', description: 'Upload file' })

        expect(tool.name).toBe('upload_file')
        expect(tool.description).toBe('Upload file')
      })

      it('uses StorageUploadInputSchema as inputSchema', () => {
        const tool = createStorageUploadTool(mockConfig)

        expect(tool.inputSchema).toBe(StorageUploadInputSchema)
      })
    })

    describe('execute', () => {
      it('uploads file with organizationId from context', async () => {
        mockStorageService.upload.mockResolvedValue({
          path: 'files/test.pdf',
          fullPath: 'org-123/files/test.pdf',
          size: 1024
        })

        const tool = createStorageUploadTool(mockConfig)
        const result = await tool.execute({
          input: {
            bucket: 'org-files',
            path: 'files/test.pdf',
            content: Buffer.from('test content').toString('base64'),
            contentType: 'application/pdf'
          },
          executionContext: mockContext
        })

        expect(mockStorageService.upload).toHaveBeenCalledWith({
          organizationId: 'org-123',
          bucket: 'org-files',
          path: 'files/test.pdf',
          file: expect.any(Buffer),
          contentType: 'application/pdf',
          upsert: undefined
        })
        expect(result).toEqual({
          success: true,
          path: 'files/test.pdf',
          fullPath: 'org-123/files/test.pdf'
        })
      })

      it('passes upsert flag when provided', async () => {
        mockStorageService.upload.mockResolvedValue({
          path: 'files/test.pdf',
          fullPath: 'org-123/files/test.pdf',
          size: 1024
        })

        const tool = createStorageUploadTool(mockConfig)
        await tool.execute({
          input: {
            bucket: 'org-files',
            path: 'files/test.pdf',
            content: Buffer.from('test').toString('base64'),
            contentType: 'application/pdf',
            upsert: true
          },
          executionContext: mockContext
        })

        expect(mockStorageService.upload).toHaveBeenCalledWith(
          expect.objectContaining({
            upsert: true
          })
        )
      })

      it('decodes base64 content to Buffer', async () => {
        mockStorageService.upload.mockResolvedValue({
          path: 'files/test.pdf',
          fullPath: 'org-123/files/test.pdf',
          size: 12
        })

        const originalContent = 'test content'
        const base64Content = Buffer.from(originalContent).toString('base64')

        const tool = createStorageUploadTool(mockConfig)
        await tool.execute({
          input: {
            bucket: 'org-files',
            path: 'files/test.pdf',
            content: base64Content,
            contentType: 'application/pdf'
          },
          executionContext: mockContext
        })

        const uploadCall = mockStorageService.upload.mock.calls[0][0]
        expect(uploadCall.file).toBeInstanceOf(Buffer)
        expect(uploadCall.file.toString()).toBe(originalContent)
      })
    })

    describe('error handling', () => {
      it('throws Error when executionContext is missing', async () => {
        const tool = createStorageUploadTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'test',
              path: 'test.pdf',
              content: 'dGVzdA==',
              contentType: 'application/pdf'
            }
          })
        ).rejects.toThrow('ExecutionContext is unavailable')
      })

      it('throws ToolingError when storageService is unavailable', async () => {
        vi.mocked(getToolServices).mockReturnValue({
          commandQueueService: null,
          taskSchedulerService: null,
          notificationsService: null,
          emailService: null,
          credentialsService: null,
          integrationService: null,
          leadService: null,
          storageService: null
        })

        const tool = createStorageUploadTool(mockConfig)

        try {
          await tool.execute({
            input: {
              bucket: 'test',
              path: 'test.pdf',
              content: 'dGVzdA==',
              contentType: 'application/pdf'
            },
            executionContext: mockContext
          })
          expect.fail('Should have thrown')
        } catch (error) {
          expect(error).toBeInstanceOf(ToolingError)
          const toolingError = error as ToolingError
          expect(toolingError.errorType).toBe('service_unavailable')
          expect(toolingError.message).toBe('StorageService is unavailable')
        }
      })

      it('propagates errors from storageService', async () => {
        mockStorageService.upload.mockRejectedValue(new Error('Upload failed'))

        const tool = createStorageUploadTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'test',
              path: 'test.pdf',
              content: 'dGVzdA==',
              contentType: 'application/pdf'
            },
            executionContext: mockContext
          })
        ).rejects.toThrow('Upload failed')
      })
    })
  })

  describe('createStorageSignedUrlTool', () => {
    describe('tool creation', () => {
      it('creates tool with correct name and description', () => {
        const tool = createStorageSignedUrlTool({
          name: 'get_signed_url',
          description: 'Get signed URL'
        })

        expect(tool.name).toBe('get_signed_url')
        expect(tool.description).toBe('Get signed URL')
      })

      it('uses StorageSignedUrlInputSchema as inputSchema', () => {
        const tool = createStorageSignedUrlTool(mockConfig)

        expect(tool.inputSchema).toBe(StorageSignedUrlInputSchema)
      })
    })

    describe('execute', () => {
      it('creates signed URL with organizationId from context', async () => {
        const expiresAt = new Date('2025-01-24T12:00:00Z')
        mockStorageService.createSignedUrl.mockResolvedValue({
          signedUrl: 'https://storage.supabase.co/signed/test-url',
          path: 'files/test.pdf',
          expiresAt
        })

        const tool = createStorageSignedUrlTool(mockConfig)
        const result = await tool.execute({
          input: {
            bucket: 'org-files',
            path: 'files/test.pdf',
            expiresIn: 3600
          },
          executionContext: mockContext
        })

        expect(mockStorageService.createSignedUrl).toHaveBeenCalledWith({
          organizationId: 'org-123',
          bucket: 'org-files',
          path: 'files/test.pdf',
          expiresIn: 3600
        })
        expect(result).toEqual({
          success: true,
          signedUrl: 'https://storage.supabase.co/signed/test-url',
          expiresAt: '2025-01-24T12:00:00.000Z'
        })
      })

      it('uses default expiresIn when not provided (via schema)', async () => {
        const expiresAt = new Date('2025-01-25T12:00:00Z')
        mockStorageService.createSignedUrl.mockResolvedValue({
          signedUrl: 'https://storage.supabase.co/signed/test-url',
          path: 'files/test.pdf',
          expiresAt
        })

        const tool = createStorageSignedUrlTool(mockConfig)
        // Parse input through schema to get default
        const parsedInput = StorageSignedUrlInputSchema.parse({
          bucket: 'org-files',
          path: 'files/test.pdf'
        })

        await tool.execute({
          input: parsedInput,
          executionContext: mockContext
        })

        expect(mockStorageService.createSignedUrl).toHaveBeenCalledWith(
          expect.objectContaining({
            expiresIn: 86400 // Default 24 hours
          })
        )
      })
    })

    describe('error handling', () => {
      it('throws Error when executionContext is missing', async () => {
        const tool = createStorageSignedUrlTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'org-files',
              path: 'files/test.pdf',
              expiresIn: 3600
            }
          })
        ).rejects.toThrow('ExecutionContext is unavailable')
      })

      it('throws ToolingError when storageService is unavailable', async () => {
        vi.mocked(getToolServices).mockReturnValue({
          commandQueueService: null,
          taskSchedulerService: null,
          notificationsService: null,
          emailService: null,
          credentialsService: null,
          integrationService: null,
          leadService: null,
          storageService: null
        })

        const tool = createStorageSignedUrlTool(mockConfig)

        try {
          await tool.execute({
            input: {
              bucket: 'org-files',
              path: 'files/test.pdf',
              expiresIn: 3600
            },
            executionContext: mockContext
          })
          expect.fail('Should have thrown')
        } catch (error) {
          expect(error).toBeInstanceOf(ToolingError)
          expect((error as ToolingError).errorType).toBe('service_unavailable')
        }
      })
    })
  })

  describe('createStorageDownloadTool', () => {
    describe('tool creation', () => {
      it('creates tool with correct name and description', () => {
        const tool = createStorageDownloadTool({
          name: 'download_file',
          description: 'Download file'
        })

        expect(tool.name).toBe('download_file')
        expect(tool.description).toBe('Download file')
      })

      it('uses StorageDownloadInputSchema as inputSchema', () => {
        const tool = createStorageDownloadTool(mockConfig)

        expect(tool.inputSchema).toBe(StorageDownloadInputSchema)
      })
    })

    describe('execute', () => {
      it('downloads file and returns base64 content', async () => {
        const fileContent = 'test file content'
        const mockBlob = new Blob([fileContent], { type: 'application/pdf' })
        mockStorageService.download.mockResolvedValue(mockBlob)

        const tool = createStorageDownloadTool(mockConfig)
        const result = await tool.execute({
          input: {
            bucket: 'org-files',
            path: 'files/test.pdf'
          },
          executionContext: mockContext
        })

        expect(mockStorageService.download).toHaveBeenCalledWith({
          organizationId: 'org-123',
          bucket: 'org-files',
          path: 'files/test.pdf'
        })
        expect(result.success).toBe(true)
        expect(result.content).toBeTruthy()
        // Verify base64 decodes back to original content
        expect(Buffer.from(result.content, 'base64').toString()).toBe(fileContent)
        expect(result.contentType).toBe('application/pdf')
      })

      it('handles blob without type', async () => {
        const mockBlob = new Blob(['content'])
        Object.defineProperty(mockBlob, 'type', { value: '' })
        mockStorageService.download.mockResolvedValue(mockBlob)

        const tool = createStorageDownloadTool(mockConfig)
        const result = await tool.execute({
          input: {
            bucket: 'org-files',
            path: 'files/test.bin'
          },
          executionContext: mockContext
        })

        expect(result.success).toBe(true)
        expect(result.contentType).toBeUndefined()
      })
    })

    describe('error handling', () => {
      it('throws Error when executionContext is missing', async () => {
        const tool = createStorageDownloadTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'org-files',
              path: 'files/test.pdf'
            }
          })
        ).rejects.toThrow('ExecutionContext is unavailable')
      })

      it('throws ToolingError when storageService is unavailable', async () => {
        vi.mocked(getToolServices).mockReturnValue({
          commandQueueService: null,
          taskSchedulerService: null,
          notificationsService: null,
          emailService: null,
          credentialsService: null,
          integrationService: null,
          leadService: null,
          storageService: null
        })

        const tool = createStorageDownloadTool(mockConfig)

        try {
          await tool.execute({
            input: {
              bucket: 'org-files',
              path: 'files/test.pdf'
            },
            executionContext: mockContext
          })
          expect.fail('Should have thrown')
        } catch (error) {
          expect(error).toBeInstanceOf(ToolingError)
          expect((error as ToolingError).errorType).toBe('service_unavailable')
        }
      })

      it('propagates errors from storageService', async () => {
        mockStorageService.download.mockRejectedValue(new Error('File not found'))

        const tool = createStorageDownloadTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'org-files',
              path: 'files/nonexistent.pdf'
            },
            executionContext: mockContext
          })
        ).rejects.toThrow('File not found')
      })
    })
  })

  describe('createStorageDeleteTool', () => {
    describe('tool creation', () => {
      it('creates tool with correct name and description', () => {
        const tool = createStorageDeleteTool({
          name: 'delete_file',
          description: 'Delete file'
        })

        expect(tool.name).toBe('delete_file')
        expect(tool.description).toBe('Delete file')
      })

      it('uses StorageDeleteInputSchema as inputSchema', () => {
        const tool = createStorageDeleteTool(mockConfig)

        expect(tool.inputSchema).toBe(StorageDeleteInputSchema)
      })
    })

    describe('execute', () => {
      it('deletes file with organizationId from context', async () => {
        mockStorageService.delete.mockResolvedValue(undefined)

        const tool = createStorageDeleteTool(mockConfig)
        const result = await tool.execute({
          input: {
            bucket: 'org-files',
            path: 'files/test.pdf'
          },
          executionContext: mockContext
        })

        expect(mockStorageService.delete).toHaveBeenCalledWith({
          organizationId: 'org-123',
          bucket: 'org-files',
          path: 'files/test.pdf'
        })
        expect(result).toEqual({ success: true })
      })
    })

    describe('error handling', () => {
      it('throws Error when executionContext is missing', async () => {
        const tool = createStorageDeleteTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'org-files',
              path: 'files/test.pdf'
            }
          })
        ).rejects.toThrow('ExecutionContext is unavailable')
      })

      it('throws ToolingError when storageService is unavailable', async () => {
        vi.mocked(getToolServices).mockReturnValue({
          commandQueueService: null,
          taskSchedulerService: null,
          notificationsService: null,
          emailService: null,
          credentialsService: null,
          integrationService: null,
          leadService: null,
          storageService: null
        })

        const tool = createStorageDeleteTool(mockConfig)

        try {
          await tool.execute({
            input: {
              bucket: 'org-files',
              path: 'files/test.pdf'
            },
            executionContext: mockContext
          })
          expect.fail('Should have thrown')
        } catch (error) {
          expect(error).toBeInstanceOf(ToolingError)
          expect((error as ToolingError).errorType).toBe('service_unavailable')
        }
      })

      it('propagates errors from storageService', async () => {
        mockStorageService.delete.mockRejectedValue(new Error('Permission denied'))

        const tool = createStorageDeleteTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'org-files',
              path: 'files/protected.pdf'
            },
            executionContext: mockContext
          })
        ).rejects.toThrow('Permission denied')
      })
    })
  })

  describe('createStorageListTool', () => {
    describe('tool creation', () => {
      it('creates tool with correct name and description', () => {
        const tool = createStorageListTool({
          name: 'list_files',
          description: 'List files'
        })

        expect(tool.name).toBe('list_files')
        expect(tool.description).toBe('List files')
      })

      it('uses StorageListInputSchema as inputSchema', () => {
        const tool = createStorageListTool(mockConfig)

        expect(tool.inputSchema).toBe(StorageListInputSchema)
      })
    })

    describe('execute', () => {
      it('lists files with organizationId from context', async () => {
        mockStorageService.list.mockResolvedValue(['file1.pdf', 'file2.png', 'file3.doc'])

        const tool = createStorageListTool(mockConfig)
        const result = await tool.execute({
          input: {
            bucket: 'org-files',
            prefix: 'proposals/'
          },
          executionContext: mockContext
        })

        expect(mockStorageService.list).toHaveBeenCalledWith({
          organizationId: 'org-123',
          bucket: 'org-files',
          prefix: 'proposals/'
        })
        expect(result).toEqual({
          success: true,
          files: ['file1.pdf', 'file2.png', 'file3.doc']
        })
      })

      it('lists files without prefix', async () => {
        mockStorageService.list.mockResolvedValue(['file1.pdf'])

        const tool = createStorageListTool(mockConfig)
        await tool.execute({
          input: {
            bucket: 'org-files'
          },
          executionContext: mockContext
        })

        expect(mockStorageService.list).toHaveBeenCalledWith({
          organizationId: 'org-123',
          bucket: 'org-files',
          prefix: undefined
        })
      })

      it('returns empty array when no files found', async () => {
        mockStorageService.list.mockResolvedValue([])

        const tool = createStorageListTool(mockConfig)
        const result = await tool.execute({
          input: {
            bucket: 'org-files',
            prefix: 'empty-folder/'
          },
          executionContext: mockContext
        })

        expect(result).toEqual({
          success: true,
          files: []
        })
      })
    })

    describe('error handling', () => {
      it('throws Error when executionContext is missing', async () => {
        const tool = createStorageListTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'org-files'
            }
          })
        ).rejects.toThrow('ExecutionContext is unavailable')
      })

      it('throws ToolingError when storageService is unavailable', async () => {
        vi.mocked(getToolServices).mockReturnValue({
          commandQueueService: null,
          taskSchedulerService: null,
          notificationsService: null,
          emailService: null,
          credentialsService: null,
          integrationService: null,
          leadService: null,
          storageService: null
        })

        const tool = createStorageListTool(mockConfig)

        try {
          await tool.execute({
            input: {
              bucket: 'org-files'
            },
            executionContext: mockContext
          })
          expect.fail('Should have thrown')
        } catch (error) {
          expect(error).toBeInstanceOf(ToolingError)
          expect((error as ToolingError).errorType).toBe('service_unavailable')
        }
      })

      it('propagates errors from storageService', async () => {
        mockStorageService.list.mockRejectedValue(new Error('Bucket not found'))

        const tool = createStorageListTool(mockConfig)

        await expect(
          tool.execute({
            input: {
              bucket: 'nonexistent-bucket'
            },
            executionContext: mockContext
          })
        ).rejects.toThrow('Bucket not found')
      })
    })
  })

  describe('concurrent execution', () => {
    it('handles multiple concurrent operations', async () => {
      mockStorageService.upload.mockResolvedValue({
        path: 'file1.pdf',
        fullPath: 'org-123/file1.pdf',
        size: 100
      })
      mockStorageService.list.mockResolvedValue(['file1.pdf', 'file2.pdf'])
      mockStorageService.createSignedUrl.mockResolvedValue({
        signedUrl: 'https://signed-url',
        path: 'file1.pdf',
        expiresAt: new Date()
      })

      const uploadTool = createStorageUploadTool({
        name: 'upload',
        description: 'Upload'
      })
      const listTool = createStorageListTool({
        name: 'list',
        description: 'List'
      })
      const signedUrlTool = createStorageSignedUrlTool({
        name: 'signed_url',
        description: 'Signed URL'
      })

      const results = await Promise.all([
        uploadTool.execute({
          input: {
            bucket: 'files',
            path: 'file1.pdf',
            content: 'dGVzdA==',
            contentType: 'application/pdf'
          },
          executionContext: mockContext
        }),
        listTool.execute({
          input: { bucket: 'files' },
          executionContext: mockContext
        }),
        signedUrlTool.execute({
          input: {
            bucket: 'files',
            path: 'file1.pdf',
            expiresIn: 3600
          },
          executionContext: mockContext
        })
      ])

      expect(results).toHaveLength(3)
      expect(results[0]).toEqual({
        success: true,
        path: 'file1.pdf',
        fullPath: 'org-123/file1.pdf'
      })
      expect(results[1]).toEqual({
        success: true,
        files: ['file1.pdf', 'file2.pdf']
      })
      expect(results[2].success).toBe(true)
      expect(results[2].signedUrl).toBe('https://signed-url')
    })
  })
})

describe('Storage Input Schemas', () => {
  describe('StorageUploadInputSchema', () => {
    it('accepts valid upload input with all required fields', () => {
      const result = StorageUploadInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf',
        content: 'dGVzdA==',
        contentType: 'application/pdf'
      })

      expect(result.success).toBe(true)
    })

    it('accepts optional upsert flag', () => {
      const result = StorageUploadInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf',
        content: 'dGVzdA==',
        contentType: 'application/pdf',
        upsert: true
      })

      expect(result.success).toBe(true)
      if (result.success) {
        expect(result.data.upsert).toBe(true)
      }
    })

    it('rejects missing bucket', () => {
      const result = StorageUploadInputSchema.safeParse({
        path: 'files/test.pdf',
        content: 'dGVzdA==',
        contentType: 'application/pdf'
      })

      expect(result.success).toBe(false)
    })

    it('rejects missing path', () => {
      const result = StorageUploadInputSchema.safeParse({
        bucket: 'org-files',
        content: 'dGVzdA==',
        contentType: 'application/pdf'
      })

      expect(result.success).toBe(false)
    })

    it('rejects missing content', () => {
      const result = StorageUploadInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf',
        contentType: 'application/pdf'
      })

      expect(result.success).toBe(false)
    })

    it('rejects missing contentType', () => {
      const result = StorageUploadInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf',
        content: 'dGVzdA=='
      })

      expect(result.success).toBe(false)
    })
  })

  describe('StorageSignedUrlInputSchema', () => {
    it('accepts valid signed URL input', () => {
      const result = StorageSignedUrlInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf',
        expiresIn: 3600
      })

      expect(result.success).toBe(true)
    })

    it('uses default expiresIn when not provided', () => {
      const result = StorageSignedUrlInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf'
      })

      expect(result.success).toBe(true)
      if (result.success) {
        expect(result.data.expiresIn).toBe(86400) // Default 24 hours
      }
    })

    it('accepts custom expiresIn value', () => {
      const result = StorageSignedUrlInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf',
        expiresIn: 604800 // 7 days
      })

      expect(result.success).toBe(true)
      if (result.success) {
        expect(result.data.expiresIn).toBe(604800)
      }
    })

    it('rejects missing bucket', () => {
      const result = StorageSignedUrlInputSchema.safeParse({
        path: 'files/test.pdf',
        expiresIn: 3600
      })

      expect(result.success).toBe(false)
    })

    it('rejects missing path', () => {
      const result = StorageSignedUrlInputSchema.safeParse({
        bucket: 'org-files',
        expiresIn: 3600
      })

      expect(result.success).toBe(false)
    })
  })

  describe('StorageDownloadInputSchema', () => {
    it('accepts valid download input', () => {
      const result = StorageDownloadInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf'
      })

      expect(result.success).toBe(true)
    })

    it('rejects missing bucket', () => {
      const result = StorageDownloadInputSchema.safeParse({
        path: 'files/test.pdf'
      })

      expect(result.success).toBe(false)
    })

    it('rejects missing path', () => {
      const result = StorageDownloadInputSchema.safeParse({
        bucket: 'org-files'
      })

      expect(result.success).toBe(false)
    })
  })

  describe('StorageDeleteInputSchema', () => {
    it('accepts valid delete input', () => {
      const result = StorageDeleteInputSchema.safeParse({
        bucket: 'org-files',
        path: 'files/test.pdf'
      })

      expect(result.success).toBe(true)
    })

    it('rejects missing bucket', () => {
      const result = StorageDeleteInputSchema.safeParse({
        path: 'files/test.pdf'
      })

      expect(result.success).toBe(false)
    })

    it('rejects missing path', () => {
      const result = StorageDeleteInputSchema.safeParse({
        bucket: 'org-files'
      })

      expect(result.success).toBe(false)
    })
  })

  describe('StorageListInputSchema', () => {
    it('accepts valid list input with prefix', () => {
      const result = StorageListInputSchema.safeParse({
        bucket: 'org-files',
        prefix: 'proposals/'
      })

      expect(result.success).toBe(true)
      if (result.success) {
        expect(result.data.prefix).toBe('proposals/')
      }
    })

    it('accepts list input without prefix', () => {
      const result = StorageListInputSchema.safeParse({
        bucket: 'org-files'
      })

      expect(result.success).toBe(true)
      if (result.success) {
        expect(result.data.prefix).toBeUndefined()
      }
    })

    it('rejects missing bucket', () => {
      const result = StorageListInputSchema.safeParse({
        prefix: 'proposals/'
      })

      expect(result.success).toBe(false)
    })
  })
})
