/**
 * TypeInference System Tests - Phase 3
 *
 * Comprehensive tests for type inference from natural language queries
 * Target: 15 tests covering all inference scenarios
 */

import { describe, it, expect, beforeEach } from 'vitest'
import { TypeInferenceSystem, inferTypes } from '../../src/query/typeInference.js'
import { NounType } from '../../src/types/graphTypes.js'

describe('TypeInference System', () => {
  let inferenceSystem: TypeInferenceSystem

  beforeEach(() => {
    inferenceSystem = new TypeInferenceSystem()
  })

  // ========== Exact Match Tests (5 tests) ==========

  describe('Exact Keyword Matching', () => {
    it('should infer Person from "engineer"', () => {
      const results = inferenceSystem.inferTypes('Find engineers')

      expect(results.length).toBeGreaterThan(0)
      expect(results[0].type).toBe(NounType.Person)
      expect(results[0].confidence).toBeGreaterThanOrEqual(0.8)
      expect(results[0].matchedKeywords).toContain('engineers')
    })

    it('should infer Location from "San Francisco"', () => {
      const results = inferenceSystem.inferTypes('people in San Francisco')

      expect(results).toContainEqual(
        expect.objectContaining({
          type: NounType.Location,
          confidence: expect.any(Number)
        })
      )

      const locationResult = results.find(r => r.type === NounType.Location)
      expect(locationResult?.confidence).toBeGreaterThanOrEqual(0.8)
    })

    it('should infer Document from "report"', () => {
      const results = inferenceSystem.inferTypes('show me the latest reports')

      expect(results.length).toBeGreaterThan(0)
      expect(results[0].type).toBe(NounType.Document)
      expect(results[0].confidence).toBeGreaterThanOrEqual(0.8)
    })

    it('should infer Organization from "company"', () => {
      const results = inferenceSystem.inferTypes('find tech companies')

      expect(results).toContainEqual(
        expect.objectContaining({
          type: NounType.Organization,
          confidence: expect.any(Number)
        })
      )

      const orgResult = results.find(r => r.type === NounType.Organization)
      expect(orgResult?.confidence).toBeGreaterThanOrEqual(0.8)
    })

    it('should infer Concept from "artificial intelligence"', () => {
      const results = inferenceSystem.inferTypes(
        'documents about artificial intelligence'
      )

      expect(results).toContainEqual(
        expect.objectContaining({
          type: NounType.Concept
        })
      )

      const conceptResult = results.find(r => r.type === NounType.Concept)
      expect(conceptResult).toBeDefined()
      expect(conceptResult?.confidence).toBeGreaterThanOrEqual(0.7)
    })
  })

  // ========== Multi-Type Tests (3 tests) ==========

  describe('Multi-Type Inference', () => {
    it('should infer [Person, Organization] from "employees at Tesla"', () => {
      const results = inferenceSystem.inferTypes('find employees at Tesla')

      expect(results.length).toBeGreaterThanOrEqual(2)

      const types = results.map(r => r.type)
      expect(types).toContain(NounType.Person)
      expect(types).toContain(NounType.Organization)
    })

    it('should infer [Document, Concept] from "papers about quantum computing"', () => {
      const results = inferenceSystem.inferTypes(
        'show papers about quantum computing'
      )

      expect(results.length).toBeGreaterThanOrEqual(2)

      const types = results.map(r => r.type)
      expect(types).toContain(NounType.Document)
      expect(types).toContain(NounType.Concept)
    })

    it('should infer [Event, Location] from "conferences in NYC"', () => {
      const results = inferenceSystem.inferTypes(
        'upcoming conferences in New York City'
      )

      expect(results.length).toBeGreaterThanOrEqual(2)

      const types = results.map(r => r.type)
      expect(types).toContain(NounType.Event)
      expect(types).toContain(NounType.Location)
    })
  })

  // ========== Confidence Tests (3 tests) ==========

  describe('Confidence Scoring', () => {
    it('should return high confidence for exact matches', () => {
      const results = inferenceSystem.inferTypes('software engineer')

      expect(results.length).toBeGreaterThan(0)
      expect(results[0].confidence).toBeGreaterThanOrEqual(0.9)
    })

    it('should return moderate confidence for partial matches', () => {
      const results = inferenceSystem.inferTypes('engineering team member')

      expect(results.length).toBeGreaterThan(0)

      // Should have multiple types matched (team → Organization, member → User, engineering → Concept)
      const types = results.map(r => r.type)
      expect(types.length).toBeGreaterThanOrEqual(2)

      // Should have Organization and User types
      expect(types).toContain(NounType.Organization)
      expect(types).toContain(NounType.User)
    })

    it('should boost confidence for multiple keyword matches', () => {
      const singleKeyword = inferenceSystem.inferTypes('engineer')
      const multiKeyword = inferenceSystem.inferTypes('software engineer developer')

      expect(singleKeyword[0].confidence).toBeLessThan(
        multiKeyword[0].confidence
      )
    })
  })

  // ========== Edge Cases (4 tests) ==========

  describe('Edge Cases', () => {
    it('should handle empty query', () => {
      const results = inferenceSystem.inferTypes('')

      expect(results).toEqual([])
    })

    it('should handle single-word query', () => {
      const results = inferenceSystem.inferTypes('documents')

      expect(results.length).toBeGreaterThan(0)
      expect(results[0].type).toBe(NounType.Document)
    })

    it('should handle very long query (100+ words)', () => {
      const longQuery =
        'Find all software engineers and developers working at technology companies ' +
        'in San Francisco and New York who have experience with artificial intelligence ' +
        'machine learning deep learning natural language processing computer vision ' +
        'data science analytics big data distributed systems cloud computing ' +
        'microservices kubernetes docker containers orchestration deployment ' +
        'continuous integration continuous deployment devops site reliability ' +
        'engineering infrastructure automation monitoring observability logging ' +
        'tracing metrics dashboards alerting incident response on call rotation'

      const results = inferenceSystem.inferTypes(longQuery)

      expect(results.length).toBeGreaterThan(0)
      expect(results[0].type).toBeDefined()

      // Should have Person, Organization, Location, Concept types
      const types = results.map(r => r.type)
      expect(types).toContain(NounType.Person)
      expect(types).toContain(NounType.Organization)
      expect(types).toContain(NounType.Location)
      expect(types).toContain(NounType.Concept)
    })

    it('should handle queries with no keyword matches', () => {
      const results = inferenceSystem.inferTypes('xyzabc qwerty asdfgh')

      expect(results).toEqual([])
    })
  })

  // ========== Performance Tests (2 tests) ==========

  describe('Performance', () => {
    it('should infer types in < 5ms', () => {
      const start = performance.now()

      inferenceSystem.inferTypes('Find software engineers in San Francisco')

      const elapsed = performance.now() - start

      expect(elapsed).toBeLessThan(5) // Target: < 1ms, allow 5ms for CI
    })

    it('should handle 100 sequential queries efficiently', () => {
      const queries = [
        'Find engineers',
        'Show documents',
        'List companies',
        'Find events',
        'Show reports'
      ]

      const start = performance.now()

      for (let i = 0; i < 100; i++) {
        inferenceSystem.inferTypes(queries[i % queries.length])
      }

      const elapsed = performance.now() - start
      const avgTime = elapsed / 100

      expect(avgTime).toBeLessThan(5) // < 5ms average per query
    })
  })

  // ========== Configuration Tests (2 tests) ==========

  describe('Configuration', () => {
    it('should respect minConfidence threshold', () => {
      const system = new TypeInferenceSystem({ minConfidence: 0.9 })

      const results = system.inferTypes('maybe a document or file')

      // High threshold should filter out low-confidence matches
      expect(results.every(r => r.confidence >= 0.9)).toBe(true)
    })

    it('should respect maxTypes limit', () => {
      const system = new TypeInferenceSystem({ maxTypes: 2 })

      const results = system.inferTypes(
        'Find engineers at companies in cities working on projects'
      )

      expect(results.length).toBeLessThanOrEqual(2)
    })
  })

  // ========== Convenience Functions (1 test) ==========

  describe('Global Convenience Functions', () => {
    it('should provide inferTypes() convenience function', () => {
      const results = inferTypes('Find engineers')

      expect(results.length).toBeGreaterThan(0)
      expect(results[0].type).toBe(NounType.Person)
    })
  })

  // ========== Statistics (1 test) ==========

  describe('System Statistics', () => {
    it('should provide keyword and phrase statistics', () => {
      const stats = inferenceSystem.getStats()

      expect(stats.keywordCount).toBeGreaterThan(500)
      expect(stats.phraseCount).toBeGreaterThan(30)
      expect(stats.config).toBeDefined()
      expect(stats.config.minConfidence).toBe(0.4)
      expect(stats.config.maxTypes).toBe(5)
    })
  })
})
