/**
 * VFS-Knowledge Separation Test (8.0)
 *
 * Exercises how VFS infrastructure entities coexist with knowledge-graph
 * entities in the same brain, and how a query opts in/out of the VFS layer:
 *
 * - VFS files/directories are real entities, marked in metadata with
 *   `isVFS: true` / `isVFSEntity: true` and `vfsType: 'file' | 'directory'`.
 * - `brain.find()` INCLUDES VFS entities by default (8.0 semantics).
 * - `brain.find({ excludeVFS: true })` drops the VFS infrastructure layer,
 *   returning only knowledge entities — works on both the metadata-filter
 *   path and the vector/`query` path.
 * - `where: { vfsType: 'file' }` selects VFS file entities explicitly.
 * - Relationships can span VFS files and knowledge entities.
 *
 * Runs under the deterministic embedder (tests/setup-integration.ts), so
 * cross-text semantic ranking is not meaningful; self-retrieval (querying an
 * entity by its own text) and `excludeVFS` filtering are.
 */

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

describe('VFS-Knowledge Separation (8.0)', () => {
  const testDir = path.join(process.cwd(), 'test-vfs-knowledge-separation')
  let brain: Brainy

  beforeAll(async () => {
    // Clean up
    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()

    // Seed the VFS layer + one knowledge entity used across the suite.
    const vfs = brain.vfs
    await vfs.init()
    await vfs.mkdir('/docs', { recursive: true })
    await vfs.writeFile('/docs/readme.md', '# Hello World')

    await brain.add({
      data: 'This is a knowledge document about AI',
      type: NounType.Document,
      metadata: {
        title: 'AI Research Paper',
        category: 'research'
      }
    })
  })

  afterAll(async () => {
    // Close releases the writer lock + flushes; prevents background-flush bleed.
    await brain.close()
    if (fs.existsSync(testDir)) {
      fs.rmSync(testDir, { recursive: true, force: true })
    }
  })

  it('includes VFS entities in brain.find() by default', async () => {
    // 8.0: VFS infrastructure entities are returned by default. The /docs/readme.md
    // file is a Document-typed entity carrying isVFS/vfsType markers, so a plain
    // type query surfaces BOTH it and the knowledge document.
    const results = await brain.find({
      type: NounType.Document,
      limit: 100
    })

    const vfsResults = results.filter((r) => r.metadata?.isVFS === true)
    const knowledgeResults = results.filter((r) => r.metadata?.isVFS !== true)

    // Default find() shows the VFS file alongside knowledge.
    expect(vfsResults.length).toBeGreaterThan(0)
    expect(knowledgeResults.length).toBeGreaterThan(0)
    expect(results.some((r) => r.metadata?.title === 'AI Research Paper')).toBe(true)
    expect(results.some((r) => r.metadata?.vfsType === 'file')).toBe(true)
  })

  it('excludes VFS entities when excludeVFS: true', async () => {
    // 8.0: excludeVFS drops the VFS infrastructure layer. Only knowledge entities remain.
    const results = await brain.find({
      type: NounType.Document,
      excludeVFS: true,
      limit: 100
    })

    const vfsResults = results.filter((r) => r.metadata?.isVFS === true)
    const knowledgeResults = results.filter((r) => r.metadata?.isVFS !== true)

    expect(vfsResults.length).toBe(0)
    expect(knowledgeResults.length).toBeGreaterThan(0)
    expect(results.some((r) => r.metadata?.title === 'AI Research Paper')).toBe(true)
  })

  it('should allow relationships between VFS files and knowledge entities', async () => {
    // Get VFS file entity. VFS files are identified by vfsType (the indexed,
    // queryable marker); they are included in find() by default.
    const vfsFile = await brain.find({
      where: {
        path: '/docs/readme.md'
      },
      limit: 1
    })
    expect(vfsFile.length).toBe(1)
    expect(vfsFile[0].metadata?.vfsType).toBe('file')

    // Get knowledge entity
    const knowledgeEntity = await brain.find({
      type: NounType.Document,
      where: {
        title: 'AI Research Paper'
      },
      excludeVFS: true,
      limit: 1
    })
    expect(knowledgeEntity.length).toBe(1)

    // Create relationship: knowledge entity -> references -> VFS file.
    // relate() returns the new relation's id (string).
    const relationId = await brain.relate({
      from: knowledgeEntity[0].id,
      to: vfsFile[0].id,
      type: VerbType.References
    })
    expect(typeof relationId).toBe('string')
    expect(relationId.length).toBeGreaterThan(0)

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

    expect(relations.length).toBe(1)
    expect(relations[0].type).toBe(VerbType.References)
  })

  it('should filter VFS entities using where clause', async () => {
    // Query for VFS files explicitly via the vfsType marker (indexed + queryable).
    const vfsFiles = await brain.find({
      where: {
        vfsType: 'file'
      },
      limit: 100
    })

    expect(vfsFiles.length).toBeGreaterThan(0)
    expect(vfsFiles.every((f) => f.metadata?.vfsType === 'file')).toBe(true)
    // Every vfsType:'file' entity is a VFS infrastructure entity.
    expect(vfsFiles.every((f) => f.metadata?.isVFS === true)).toBe(true)

    // Query for non-VFS knowledge entities explicitly via a user metadata field.
    const nonVFS = await brain.find({
      where: {
        category: 'research'
      },
      limit: 100
    })

    expect(nonVFS.length).toBeGreaterThan(0)
    expect(nonVFS.every((e) => e.metadata?.isVFS !== true)).toBe(true)
    expect(nonVFS.every((e) => e.metadata?.vfsType === undefined)).toBe(true)
  })

  it('should handle semantic search with VFS filtering', async () => {
    // Self-retrieval: querying with the knowledge doc's own text returns it
    // (deterministic embedder ⇒ cosine 1.0). With excludeVFS the VFS layer is dropped.
    const knowledgeOnly = await brain.find({
      query: 'This is a knowledge document about AI',
      excludeVFS: true,
      limit: 10
    })
    expect(knowledgeOnly.length).toBeGreaterThan(0)
    expect(knowledgeOnly.some((r) => r.metadata?.isVFS === true)).toBe(false)
    expect(knowledgeOnly.some((r) => r.metadata?.title === 'AI Research Paper')).toBe(true)

    // Default (no excludeVFS): self-retrieval of the VFS file by its own content
    // returns it — VFS entities participate in vector search by default.
    const withVFS = await brain.find({
      query: '# Hello World',
      limit: 10
    })
    expect(withVFS.some((r) => r.metadata?.path === '/docs/readme.md')).toBe(true)

    // excludeVFS on the vector path removes the VFS file even when its content matches.
    const withVFSExcluded = await brain.find({
      query: '# Hello World',
      excludeVFS: true,
      limit: 10
    })
    expect(withVFSExcluded.some((r) => r.metadata?.isVFS === true)).toBe(false)
  })
})
