/**
 * VFS API Wiring Verification Test
 *
 * Verifies the VFS-related APIs are wired into the rest of Brainy and honour the
 * 8.0 VFS-visibility contract: VFS entities are INCLUDED by default in find() /
 * similar(), and `excludeVFS: true` is the opt-out that keeps the knowledge graph
 * clean. Also exercises vfs.search/findSimilar/searchEntities, VFS metadata
 * projections, VFS↔knowledge relationships, and batch-scale querying.
 *
 * This test catches "created but not wired up" bugs.
 */

import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import { Brainy } from '../../src/brainy.js'
import { NounType } from '../../src/types/graphTypes.js'
import * as fs from 'fs'
import * as path from 'path'

describe('VFS API Wiring Verification', () => {
  const testDir = path.join(process.cwd(), 'test-vfs-api-wiring')
  let brain: Brainy

  beforeAll(async () => {
    if (fs.existsSync(testDir)) {
      fs.rmSync(testDir, { recursive: true, force: true })
    }
    fs.mkdirSync(testDir, { recursive: true })

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

  afterAll(async () => {
    // Close the brain so the writer lock is released and the background flush /
    // heartbeat timers stop — otherwise teardown can hang ~8s and bleed state.
    await brain.close()
    if (fs.existsSync(testDir)) {
      fs.rmSync(testDir, { recursive: true, force: true })
    }
  })

  it('should verify brain.similar() properly filters VFS', async () => {
    console.log('\n📋 Test 1: brain.similar() VFS filtering')

    // Create knowledge entity
    const knowledgeId = await brain.add({
      data: 'Knowledge about TypeScript',
      type: NounType.Document,
      metadata: { topic: 'programming' }
    })

    // Create VFS file
    const vfs = brain.vfs
    await vfs.init()
    await vfs.writeFile('/typescript.md', 'TypeScript programming guide')

    // Test 1a: similar() with DEFAULT VFS handling.
    // 8.0 contract (SimilarParams.excludeVFS, default false): VFS entities are
    // INCLUDED by default. The opt-OUT is `excludeVFS: true`.
    const similarWithVFS = await brain.similar({
      to: knowledgeId,
      limit: 10
    })

    console.log(`   similar() default (VFS included): ${similarWithVFS.length} results`)
    const hasVFS1 = similarWithVFS.some(r => r.metadata?.isVFS === true)
    console.log(`   Contains VFS: ${hasVFS1}`)

    expect(hasVFS1).toBe(true) // VFS included by default in 8.0

    // Test 1b: similar() WITH excludeVFS: true (should exclude VFS)
    const similarWithoutVFS = await brain.similar({
      to: knowledgeId,
      limit: 10,
      excludeVFS: true
    })

    console.log(`   similar() with excludeVFS: ${similarWithoutVFS.length} results`)
    const hasVFS2 = similarWithoutVFS.some(r => r.metadata?.isVFS === true)
    console.log(`   Contains VFS: ${hasVFS2}`)

    expect(hasVFS2).toBe(false) // excludeVFS removes VFS entities
    // The default (VFS included) returns strictly more than excludeVFS.
    expect(similarWithVFS.length).toBeGreaterThan(similarWithoutVFS.length)
  })

  it('should verify vfs.search() finds VFS files', async () => {
    console.log('\n📋 Test 2: vfs.search() finds VFS files')

    const vfs = brain.vfs
    await vfs.init()  // Required before using VFS operations

    // Create test files
    await vfs.writeFile('/docs/readme.md', 'Project documentation')
    await vfs.writeFile('/docs/api.md', 'API reference guide')

    // Search for files
    const results = await vfs.search('documentation', { limit: 10 })

    console.log(`   VFS search results: ${results.length}`)
    if (results.length > 0) {
      console.log(`   First result structure:`, JSON.stringify(results[0], null, 2))
      // Check for results without path
      const noPaths = results.filter(r => !r.path)
      if (noPaths.length > 0) {
        console.log(`   ⚠️ ${noPaths.length} results without path:`, noPaths.map(r => ({ entityId: r.entityId, path: r.path })))
      }
    }

    expect(results.length).toBeGreaterThan(0) // Should find VFS files
    // Verify all results are valid VFS search results with path property
    expect(results.every(r => typeof r.path === 'string' && r.path.length > 0)).toBe(true)
    expect(results.every(r => typeof r.entityId === 'string')).toBe(true)
    expect(results.some(r => r.path.includes('readme'))).toBe(true)
  })

  it('should verify vfs.findSimilar() finds similar VFS files', async () => {
    console.log('\n📋 Test 3: vfs.findSimilar() finds similar VFS files')

    const vfs = brain.vfs
    await vfs.init()  // Required before using VFS operations

    // Create similar files
    await vfs.writeFile('/code/server.ts', 'Server implementation')
    await vfs.writeFile('/code/client.ts', 'Client implementation')
    await vfs.writeFile('/code/utils.ts', 'Utility functions')

    // Find files similar to server.ts
    const similar = await vfs.findSimilar('/code/server.ts', { limit: 10 })

    console.log(`   Similar files: ${similar.length}`)
    if (similar.length > 0) {
      console.log(`   First result structure:`, JSON.stringify(similar[0], null, 2))
      // Check for results without path
      const noPaths = similar.filter(r => !r.path)
      if (noPaths.length > 0) {
        console.log(`   ⚠️ ${noPaths.length} results without path:`, noPaths.map(r => ({ entityId: r.entityId, path: r.path })))
      }
    }

    expect(similar.length).toBeGreaterThan(0) // Should find similar VFS files
    // Verify all results are valid VFS search results with path property
    expect(similar.every(r => typeof r.path === 'string' && r.path.length > 0)).toBe(true)
    expect(similar.every(r => typeof r.entityId === 'string')).toBe(true)
    // Should find at least one of our created files
    expect(similar.some(r => r.path.includes('/code/'))).toBe(true)
  })

  it('should verify vfs.searchEntities() finds VFS entities', async () => {
    console.log('\n📋 Test 4: vfs.searchEntities() finds VFS entities')

    const vfs = brain.vfs
    await vfs.init()  // Required before using VFS operations

    // Create entity in VFS (if supported)
    await vfs.mkdir('/entities', { recursive: true })

    // Search for entities
    const results = await vfs.searchEntities({
      type: 'entity',
      limit: 10
    })

    console.log(`   VFS entity search results: ${results.length}`)

    // Should work without errors (even if no entities exist yet)
    expect(Array.isArray(results)).toBe(true)
  })

  it('should verify VFS semantic projections work', async () => {
    console.log('\n📋 Test 5: VFS semantic projections')

    const vfs = brain.vfs
    await vfs.init()  // Required before using VFS operations

    // Create files with metadata for projections
    await vfs.writeFile('/project/feature.ts', 'Feature implementation', {
      extractMetadata: false  // Manual metadata
    })

    // Get the file entity and update with tags/owner.
    // 8.0: VFS entities are included in find() by default (excludeVFS opts out),
    // so no include flag is needed to retrieve a VFS file by path.
    const fileResults = await brain.find({
      where: { path: '/project/feature.ts' },
      limit: 1
    })

    if (fileResults.length > 0) {
      const fileId = fileResults[0].id

      // Add metadata for semantic projections
      await brain.update({
        id: fileId,
        metadata: {
          ...fileResults[0].metadata,
          tags: ['typescript', 'feature'],
          owner: 'developer1'
        }
      })

      // Test tag-based query.
      // `tags` is a multi-valued (array) metadata field; per QUERY_OPERATORS.md
      // `{ tags: { contains: 'typescript' } }` must match an entity whose tags
      // array contains 'typescript'. The file's tags are ['typescript','feature'].
      const tagResults = await brain.find({
        where: {
          vfsType: 'file',
          tags: { contains: 'typescript' }
        },
        limit: 10
      })

      console.log(`   Tag-based search: ${tagResults.length} results`)
      expect(tagResults.length).toBeGreaterThan(0)

      // Test owner-based query
      const ownerResults = await brain.find({
        where: {
          vfsType: 'file',
          owner: 'developer1'
        },
        limit: 10
      })

      console.log(`   Owner-based search: ${ownerResults.length} results`)
      expect(ownerResults.length).toBeGreaterThan(0)
    }
  })

  it('should verify excludeVFS keeps the knowledge graph clean', async () => {
    console.log('\n📋 Test 6: Knowledge graph cleanliness via excludeVFS')

    // 8.0 contract (FindParams.excludeVFS, default false): VFS entities are
    // INCLUDED by default, so a plain type query returns both knowledge AND VFS.
    const withVFS = await brain.find({
      type: [NounType.Document, NounType.File],
      limit: 100
    })
    const leakedByDefault = withVFS.filter(r => r.metadata?.isVFS === true).length
    console.log(`   Default query VFS entities: ${leakedByDefault}`)
    expect(leakedByDefault).toBeGreaterThan(0) // VFS is included by default in 8.0

    // The opt-OUT — excludeVFS: true — yields a clean knowledge-only result set.
    const knowledge = await brain.find({
      type: [NounType.Document, NounType.File],
      excludeVFS: true,
      limit: 100
    })

    const vfsCount = knowledge.filter(r => r.metadata?.isVFS === true).length
    const knowledgeCount = knowledge.filter(r => r.metadata?.isVFS !== true).length

    console.log(`   Knowledge entities: ${knowledgeCount}`)
    console.log(`   VFS entities leaked: ${vfsCount}`)

    // With excludeVFS the knowledge graph is clean (no VFS)
    expect(vfsCount).toBe(0)
    expect(knowledgeCount).toBeGreaterThan(0)
  })

  it('should verify VFS-knowledge relationships work', async () => {
    console.log('\n📋 Test 7: VFS-knowledge relationships')

    // Create knowledge entity
    const conceptId = await brain.add({
      data: 'Server architecture concept',
      type: NounType.Concept,
      metadata: { category: 'architecture' }
    })

    // Get VFS file (created in Test 3). VFS entities are included in find() by
    // default in 8.0, so no include flag is needed.
    const vfsFile = await brain.find({
      where: { path: '/code/server.ts' },
      limit: 1
    })

    if (vfsFile.length > 0) {
      // Create relationship: concept -> implements -> file
      const relationId = await brain.relate({
        from: conceptId,
        to: vfsFile[0].id,
        type: 'implements'
      })

      console.log(`   Created relation: ${relationId}`)

      // Verify relationship exists
      const relations = await brain.related({
        from: conceptId,
        to: vfsFile[0].id
      })

      expect(relations.length).toBe(1)
      expect(relations[0].type).toBe('implements')
      console.log(`   ✅ VFS-knowledge relationship verified`)
    }
  })

  it('should verify production scale performance', async () => {
    console.log('\n📋 Test 8: Production scale performance')

    const vfs = brain.vfs
    await vfs.init()  // Required before using VFS operations

    // Create batch of files
    const createStart = Date.now()
    for (let i = 0; i < 50; i++) {
      await vfs.writeFile(`/batch/file${i}.txt`, `Content ${i}`)
    }
    const createTime = Date.now() - createStart
    console.log(`   Created 50 files in ${createTime}ms`)

    // Search performance
    const searchStart = Date.now()
    const searchResults = await vfs.search('Content', { limit: 100 })
    const searchTime = Date.now() - searchStart
    console.log(`   Searched in ${searchTime}ms, found ${searchResults.length} results`)

    // Metadata query performance (uses O(log n) index). VFS entities are
    // included in find() by default in 8.0, so no include flag is needed.
    const metaStart = Date.now()
    const metaResults = await brain.find({
      where: { vfsType: 'file' },
      limit: 100
    })
    const metaTime = Date.now() - metaStart
    console.log(`   Metadata query in ${metaTime}ms, found ${metaResults.length} results`)

    // Performance assertions — thresholds relaxed x5 over the original budgets
    // (1000ms / 500ms) so they're a generous regression guard, not an
    // env-dependent flake on shared/throttled CI.
    expect(searchTime).toBeLessThan(5000) // PERF: env-dependent (was < 1s)
    expect(metaTime).toBeLessThan(2500) // PERF: env-dependent (was < 500ms, O(log n) index)
    // Functional assertions — real behavior, not relaxed.
    expect(searchResults.length).toBeGreaterThan(0)
    expect(metaResults.length).toBeGreaterThan(50)
  })
})
