import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { Brainy } from '../../../src/brainy.js'
import { VirtualFileSystem } from '../../../src/vfs/VirtualFileSystem.js'
import * as fs from 'fs/promises'
import * as path from 'path'

/**
 * v5.2.0: Test unified BlobStorage integration with VFS
 *
 * This test verifies that:
 * 1. All files (small, medium, large) use BlobStorage
 * 2. No size-based branching occurs
 * 3. Content is stored and retrieved correctly
 * 4. Deduplication works automatically
 *
 * Note: Uses FileSystemStorage because BlobStorage is only available
 * in COW-enabled storage adapters (not MemoryStorage)
 */
describe('VFS Unified BlobStorage (v5.2.0)', () => {
  let brain: Brainy
  let vfs: VirtualFileSystem
  let testDir: string

  beforeEach(async () => {
    // Create temporary directory for test storage
    testDir = path.join('/tmp', `brainy-test-blob-${Date.now()}-${Math.random().toString(36).slice(2)}`)
    await fs.mkdir(testDir, { recursive: true })

    brain = new Brainy({ requireSubtype: false,
      storage: {
        type: 'filesystem',
        path: testDir
      },
      silent: true
    })
    await brain.init()
    vfs = brain.vfs
  })

  afterEach(async () => {
    await brain.close()

    // Clean up temporary directory
    try {
      await fs.rm(testDir, { recursive: true, force: true })
    } catch (error) {
      // Ignore cleanup errors
    }
  })

  describe('Unified Storage Path', () => {
    it('should store small files (<100KB) in BlobStorage', async () => {
      const content = 'Small file content'
      await vfs.writeFile('/small.txt', content)

      // Get entity directly using VFS API
      const entity = await vfs.getEntity('/small.txt')

      expect(entity.metadata.vfsType).toBe('file')
      expect(entity.metadata.storage?.type).toBe('blob')
      expect(entity.metadata.storage?.hash).toBeDefined()

      const readContent = await vfs.readFile('/small.txt')
      expect(readContent.toString()).toBe(content)
    })

    it('should store medium files (100KB-10MB) in BlobStorage', async () => {
      const content = Buffer.alloc(200_000, 'M') // 200KB
      await vfs.writeFile('/medium.bin', content)

      const entity = await vfs.getEntity('/medium.bin')

      expect(entity.metadata.vfsType).toBe('file')
      expect(entity.metadata.storage?.type).toBe('blob')
      expect(entity.metadata.storage?.hash).toBeDefined()

      const readContent = await vfs.readFile('/medium.bin')
      expect(Buffer.compare(readContent, content)).toBe(0)
    })

    it('should store large files (>10MB) in BlobStorage', async () => {
      const content = Buffer.alloc(11_000_000, 'L') // 11MB
      await vfs.writeFile('/large.bin', content)

      const entity = await vfs.getEntity('/large.bin')

      expect(entity.metadata.vfsType).toBe('file')
      expect(entity.metadata.storage?.type).toBe('blob')
      expect(entity.metadata.storage?.hash).toBeDefined()

      const readContent = await vfs.readFile('/large.bin')
      expect(Buffer.compare(readContent, content)).toBe(0)
    })
  })

  describe('Deduplication', () => {
    it('should deduplicate identical files', async () => {
      const content = 'Duplicate content test'

      // Write same content to two different paths
      await vfs.writeFile('/file1.txt', content)
      await vfs.writeFile('/file2.txt', content)

      // Get entities directly
      const entity1 = await vfs.getEntity('/file1.txt')
      const entity2 = await vfs.getEntity('/file2.txt')

      // Both should have blob storage
      expect(entity1.metadata.storage?.type).toBe('blob')
      expect(entity2.metadata.storage?.type).toBe('blob')

      // But same blob hash (deduplicated)
      const hash1 = entity1.metadata.storage?.hash
      const hash2 = entity2.metadata.storage?.hash

      expect(hash1).toBeDefined()
      expect(hash2).toBeDefined()
      expect(hash1).toBe(hash2) // Same content = same hash
    })
  })

  describe('File Operations', () => {
    it('should update files correctly', async () => {
      await vfs.writeFile('/update.txt', 'Original content')
      await vfs.writeFile('/update.txt', 'Updated content')

      const content = await vfs.readFile('/update.txt')
      expect(content.toString()).toBe('Updated content')
    })

    it('should delete files and decrement blob refs', async () => {
      await vfs.writeFile('/delete.txt', 'Delete me')

      await vfs.unlink('/delete.txt')

      await expect(vfs.readFile('/delete.txt')).rejects.toThrow()
    })

    it('should append to files', async () => {
      await vfs.writeFile('/append.txt', 'First part')
      await vfs.appendFile('/append.txt', ' Second part')

      const content = await vfs.readFile('/append.txt')
      expect(content.toString()).toBe('First part Second part')
    })
  })

  describe('Binary Files', () => {
    it('should handle binary files correctly', async () => {
      const binary = Buffer.from([0x00, 0xFF, 0xAB, 0xCD, 0xEF])
      await vfs.writeFile('/binary.dat', binary)

      const read = await vfs.readFile('/binary.dat')
      expect(Buffer.compare(read, binary)).toBe(0)
    })

    it('should preserve binary file integrity', async () => {
      // Create a buffer with various byte patterns
      const buffer = Buffer.alloc(1000)
      for (let i = 0; i < 1000; i++) {
        buffer[i] = i % 256
      }

      await vfs.writeFile('/integrity.bin', buffer)
      const read = await vfs.readFile('/integrity.bin')

      expect(Buffer.compare(read, buffer)).toBe(0)
      expect(read.length).toBe(buffer.length)
    })
  })

  describe('Metadata', () => {
    it('should store correct metadata', async () => {
      const content = 'Test file'
      await vfs.writeFile('/meta.txt', content)

      const entity = await vfs.getEntity('/meta.txt')

      expect(entity.metadata.size).toBe(content.length)
      expect(entity.metadata.vfsType).toBe('file')
      expect(entity.metadata.storage?.type).toBe('blob')
      expect(entity.metadata.storage?.size).toBe(content.length)
      expect(entity.metadata.mimeType).toBeDefined()
    })
  })

})
