/**
 * OPFS Storage Tests
 * Tests for the OPFS storage adapter using a simulated OPFS environment
 */

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { setupOPFSMock, cleanupOPFSMock } from './mocks/opfs-mock'
import { Vector } from '../src/coreTypes'

describe('OPFSStorage', () => {
  // Import modules inside tests to avoid issues with dynamic imports
  let OPFSStorage: any
  let opfsMock: any

  beforeEach(async () => {
    // Setup OPFS mock environment
    opfsMock = setupOPFSMock()
    
    // Import storage factory
    const storageFactory = await import('../src/storage/storageFactory.js')
    OPFSStorage = storageFactory.OPFSStorage
  })

  afterEach(() => {
    // Clean up OPFS mock environment
    cleanupOPFSMock()
    
    // Reset mocks
    vi.resetAllMocks()
  })

  it('should detect OPFS availability correctly', () => {
    // Create a new instance with our mocked environment
    const opfsStorage = new OPFSStorage()
    
    // With our mocks in place, OPFS should be available
    expect(opfsStorage.isOPFSAvailable()).toBe(true)
    
    // Now remove the getDirectory method to simulate OPFS not being available
    delete global.navigator.storage.getDirectory
    
    // Create a new instance with the modified environment
    const opfsStorage2 = new OPFSStorage()
    expect(opfsStorage2.isOPFSAvailable()).toBe(false)
  })

  it('should initialize and perform basic operations with OPFS storage', async () => {
    // Create a new instance with our mocked environment
    const opfsStorage = new OPFSStorage()
    
    // Initialize the storage
    await opfsStorage.init()
    
    // Test basic metadata operations
    const testMetadata = { test: 'data', value: 123 }
    await opfsStorage.saveMetadata('test-key', testMetadata)
    
    const retrievedMetadata = await opfsStorage.getMetadata('test-key')
    expect(retrievedMetadata).toEqual(testMetadata)
    
    // Clean up
    await opfsStorage.clearAll({ force: true })
  })

  it('should handle noun operations correctly', async () => {
    // Create a new instance with our mocked environment
    const opfsStorage = new OPFSStorage()
    
    // Initialize the storage
    await opfsStorage.init()
    
    // Create test noun
    const testVector: Vector = [0.1, 0.2, 0.3, 0.4, 0.5]
    const testNoun = {
      id: 'test-noun-1',
      vector: testVector,
      connections: new Map([
        [0, new Set(['test-noun-2', 'test-noun-3'])]
      ])
    }
    
    // Save the noun
    await opfsStorage.saveNoun(testNoun)
    
    // Retrieve the noun
    const retrievedNoun = await opfsStorage.getNoun('test-noun-1')
    
    // Verify the noun was saved and retrieved correctly
    expect(retrievedNoun).toBeDefined()
    expect(retrievedNoun?.id).toBe('test-noun-1')
    expect(retrievedNoun?.vector).toEqual(testVector)
    
    // Verify connections were saved correctly
    // Note: connections are stored as a Map in memory but might be serialized differently
    expect(retrievedNoun?.connections).toBeDefined()
    expect(retrievedNoun?.connections.get(0)).toBeDefined()
    expect(retrievedNoun?.connections.get(0)?.has('test-noun-2')).toBe(true)
    expect(retrievedNoun?.connections.get(0)?.has('test-noun-3')).toBe(true)
    
    // Check if the noun is actually stored first
    console.log('DEBUG: Checking if noun exists after save')
    const storedNoun = await opfsStorage.getNoun('test-noun-1')
    console.log('DEBUG: storedNoun:', storedNoun ? 'EXISTS' : 'NOT FOUND')
    
    // Test getNouns with pagination
    console.log('DEBUG: About to test getNouns')
    const nounsResult = await opfsStorage.getNouns({ pagination: { limit: 10 } })
    console.log('DEBUG: getNouns result:', nounsResult.items.length)
    
    expect(nounsResult.items.length).toBe(1)
    expect(nounsResult.items[0].id).toBe('test-noun-1')
    
    // Test deleteNoun
    await opfsStorage.deleteNoun('test-noun-1')
    const deletedNoun = await opfsStorage.getNoun('test-noun-1')
    expect(deletedNoun).toBeNull()
    
    // Clean up
    await opfsStorage.clearAll({ force: true })
  })

  it('should handle verb operations correctly', async () => {
    // Create a new instance with our mocked environment
    const opfsStorage = new OPFSStorage()
    
    // Initialize the storage
    await opfsStorage.init()
    
    // Create test verb
    const testVector: Vector = [0.1, 0.2, 0.3, 0.4, 0.5]
    const timestamp = {
      seconds: Math.floor(Date.now() / 1000),
      nanoseconds: (Date.now() % 1000) * 1000000
    }
    const testVerb = {
      id: 'test-verb-1',
      vector: testVector,
      connections: new Map(),
      source: 'source-noun-1',
      target: 'target-noun-1',
      verb: 'test-relation',
      weight: 0.75,
      metadata: { description: 'Test relation' },
      createdAt: timestamp,
      updatedAt: timestamp,
      createdBy: {
        augmentation: 'test-service',
        version: '1.0'
      }
    }
    
    // Save the verb
    await opfsStorage.saveVerb(testVerb)
    
    // Retrieve the verb
    const retrievedVerb = await opfsStorage.getVerb('test-verb-1')
    
    // Verify the verb was saved and retrieved correctly
    expect(retrievedVerb).toBeDefined()
    expect(retrievedVerb?.id).toBe('test-verb-1')
    expect(retrievedVerb?.vector).toEqual(testVector)
    expect(retrievedVerb?.source).toBe('source-noun-1')
    expect(retrievedVerb?.target).toBe('target-noun-1')
    expect(retrievedVerb?.verb).toBe('test-relation')
    expect(retrievedVerb?.weight).toBe(0.75)
    expect(retrievedVerb?.metadata).toEqual({ description: 'Test relation' })
    expect(retrievedVerb?.createdAt).toEqual(timestamp)
    expect(retrievedVerb?.updatedAt).toEqual(timestamp)
    expect(retrievedVerb?.createdBy).toEqual({
      augmentation: 'test-service',
      version: '1.0'
    })
    
    // Test getVerbs with pagination
    const verbsResult = await opfsStorage.getVerbs({ pagination: { limit: 10 } })
    expect(verbsResult.items.length).toBe(1)
    expect(verbsResult.items[0].id).toBe('test-verb-1')
    
    // Test getVerbsBySource
    const verbsBySource = await opfsStorage.getVerbsBySource('source-noun-1')
    expect(verbsBySource.length).toBe(1)
    expect(verbsBySource[0].id).toBe('test-verb-1')
    
    // Test getVerbsByTarget
    const verbsByTarget = await opfsStorage.getVerbsByTarget('target-noun-1')
    expect(verbsByTarget.length).toBe(1)
    expect(verbsByTarget[0].id).toBe('test-verb-1')
    
    // Test getVerbsByType
    const verbsByType = await opfsStorage.getVerbsByType('test-relation')
    expect(verbsByType.length).toBe(1)
    expect(verbsByType[0].id).toBe('test-verb-1')
    
    // Test deleteVerb
    await opfsStorage.deleteVerb('test-verb-1')
    const deletedVerb = await opfsStorage.getVerb('test-verb-1')
    expect(deletedVerb).toBeNull()
    
    // Clean up
    await opfsStorage.clearAll({ force: true })
  })

  it('should handle storage status correctly', async () => {
    // Create a new instance with our mocked environment
    const opfsStorage = new OPFSStorage()
    
    // Initialize the storage
    await opfsStorage.init()
    
    // Add some data to the storage
    const testVector: Vector = [0.1, 0.2, 0.3, 0.4, 0.5]
    const testNoun = {
      id: 'test-noun-1',
      vector: testVector,
      connections: new Map([
        [0, new Set(['test-noun-2', 'test-noun-3'])]
      ])
    }
    
    await opfsStorage.saveNoun(testNoun)
    await opfsStorage.saveMetadata('test-key', { test: 'data', value: 123 })
    
    // Get storage status
    const status = await opfsStorage.getStorageStatus()
    
    // Verify status
    expect(status.type).toBe('opfs')
    expect(status.used).toBeGreaterThan(0)
    expect(status.quota).toBeGreaterThan(0)
    
    // Clean up
    await opfsStorage.clearAll({ force: true })
  })

  it('should handle persistence correctly', async () => {
    // Create a new instance with our mocked environment
    const opfsStorage = new OPFSStorage()
    
    // Initialize the storage
    await opfsStorage.init()
    
    // Test persistence methods
    const isPersisted = await opfsStorage.isPersistent()
    expect(isPersisted).toBe(true)
    
    // Get the current persistence state
    const initialPersistence = await opfsStorage.isPersistent()
    expect(initialPersistence).toBe(true)
    
    // Request persistence (should return true with our mock)
    const persistResult = await opfsStorage.requestPersistentStorage()
    expect(persistResult).toBe(true)
    
    // Clean up
    await opfsStorage.clearAll({ force: true })
  })
})