/**
 * @module tests/integration/find-triple-composition
 * @description Correctness of Triple-Intelligence composition in `find()`: a single
 * query combining vector similarity, metadata filtering, and graph traversal must
 * return exactly the entities satisfying ALL three constraints — never silently drop
 * a row that each pairwise query would return. Guards the headline 8.0 query surface.
 */
import { describe, it, expect, afterEach } from 'vitest'
import { Brainy } from '../../src/brainy.js'
import { NounType, VerbType } from '../../src/types/graphTypes.js'

/** Deterministic 384-dim vector; same seed ⇒ identical vector (distance 0). */
function vec(seed: number): number[] {
  return Array.from({ length: 384 }, (_, i) => ((seed * 31 + i * 7) % 100) / 100)
}

describe('find() Triple-Intelligence composition', () => {
  const brains: Brainy[] = []
  afterEach(async () => {
    for (const b of brains.splice(0)) await b.close()
  })
  async function open(): Promise<Brainy> {
    const b = new Brainy({ storage: { type: 'memory' }, eagerEmbeddings: false, requireSubtype: false, silent: true })
    await b.init()
    brains.push(b)
    return b
  }

  it('returns the entity satisfying vector ∩ metadata ∩ graph; excludes those failing any one', async () => {
    const brain = await open()
    const hub = await brain.add({ vector: vec(1), type: NounType.Document, metadata: { role: 'hub', category: 9 } })
    // Connected neighbours of the hub:
    const n1 = await brain.add({ vector: vec(10), type: NounType.Document, metadata: { role: 'n1', category: 3 } })
    const n2 = await brain.add({ vector: vec(11), type: NounType.Document, metadata: { role: 'n2', category: 3 } })
    const n3 = await brain.add({ vector: vec(12), type: NounType.Document, metadata: { role: 'n3', category: 7 } })
    // Decoys: vector-identical to n1 (seed 10) and category 3, but NOT connected to the hub.
    const decoys: string[] = []
    for (let i = 0; i < 5; i++) {
      decoys.push(await brain.add({ vector: vec(10), type: NounType.Document, metadata: { role: 'decoy', category: 3 } }))
    }
    await brain.relate({ from: hub, to: n1, type: VerbType.References, weight: 1 })
    await brain.relate({ from: hub, to: n2, type: VerbType.References, weight: 1 })
    await brain.relate({ from: hub, to: n3, type: VerbType.References, weight: 1 })

    const roles = (r: Array<{ metadata?: any }>) => new Set(r.map((x) => x.metadata?.role))

    // Sanity: each single/pairwise constraint behaves.
    const graphOut = await brain.find({
      connected: { from: hub, via: VerbType.References, direction: 'out', depth: 1 }, limit: 50
    })
    expect(roles(graphOut)).toEqual(new Set(['n1', 'n2', 'n3']))

    // Full triple: near vec(10) (n1 + decoys) AND category 3 (n1, n2, decoys) AND connected to hub (n1,n2,n3).
    // The intersection is exactly {n1}. Decoys fail graph; n2 fails vector(distance); n3 fails category.
    const triple = await brain.find({
      vector: vec(10),
      where: { category: 3 },
      connected: { from: hub, via: VerbType.References, direction: 'out', depth: 1 },
      limit: 50
    })
    const got = roles(triple)
    expect(got.size).toBeGreaterThan(0)          // composition must not be empty
    expect(got.has('n1')).toBe(true)             // n1 satisfies all three — must be present
    expect(got.has('decoy')).toBe(false)         // decoys fail the graph constraint
    expect(got.has('hub')).toBe(false)           // hub is category 9
  })
})
