/**
 * Type-Aware Query Planner - Phase 3: Type-First Query Optimization
 *
 * Generates optimized query execution plans by inferring entity types from
 * natural language queries using semantic similarity and routing to specific
 * TypeAwareHNSWIndex graphs.
 *
 * Performance Impact:
 * - Single-type queries: 31x speedup (search 1/31 graphs)
 * - Multi-type queries: 6-15x speedup (search 2-5/31 graphs)
 * - Overall: 40% latency reduction @ 1B scale
 *
 * Examples:
 * - "Find engineers" → single-type → [Person] → 31x speedup
 * - "People at Tesla" → multi-type → [Person, Organization] → 15.5x speedup
 * - "Everything about AI" → all-types → [all 31 types] → no speedup
 */

import { NounType, NOUN_TYPE_COUNT } from '../types/graphTypes.js'
import { inferNouns, type TypeInference } from './semanticTypeInference.js'
import { prodLog } from '../utils/logger.js'

/**
 * Query routing strategy
 */
export type QueryRoutingStrategy = 'single-type' | 'multi-type' | 'all-types'

/**
 * Optimized query execution plan
 */
export interface TypeAwareQueryPlan {
  /**
   * Original natural language query
   */
  originalQuery: string

  /**
   * Inferred types with confidence scores
   */
  inferredTypes: TypeInference[]

  /**
   * Selected routing strategy
   */
  routing: QueryRoutingStrategy

  /**
   * Target types to search (1-31 types)
   */
  targetTypes: NounType[]

  /**
   * Estimated speedup factor (1.0 = no speedup, 31.0 = 31x faster)
   */
  estimatedSpeedup: number

  /**
   * Overall confidence in the plan (0.0-1.0)
   */
  confidence: number

  /**
   * Reasoning for the routing decision (for debugging/analytics)
   */
  reasoning: string
}

/**
 * Configuration for query planner behavior
 */
export interface QueryPlannerConfig {
  /**
   * Minimum confidence for single-type routing (default: 0.8)
   */
  singleTypeThreshold?: number

  /**
   * Minimum confidence for multi-type routing (default: 0.6)
   */
  multiTypeThreshold?: number

  /**
   * Maximum types for multi-type routing (default: 5)
   */
  maxMultiTypes?: number

  /**
   * Enable debug logging (default: false)
   */
  debug?: boolean
}

/**
 * Query pattern statistics for learning
 */
interface QueryStats {
  totalQueries: number
  singleTypeQueries: number
  multiTypeQueries: number
  allTypesQueries: number
  avgConfidence: number
}

/**
 * Type-Aware Query Planner
 *
 * Generates optimized query plans using semantic type inference to route queries
 * to specific TypeAwareHNSWIndex graphs for billion-scale performance.
 */
export class TypeAwareQueryPlanner {
  private config: Required<QueryPlannerConfig>
  private stats: QueryStats

  constructor(config?: QueryPlannerConfig) {
    this.config = {
      singleTypeThreshold: config?.singleTypeThreshold ?? 0.8,
      multiTypeThreshold: config?.multiTypeThreshold ?? 0.6,
      maxMultiTypes: config?.maxMultiTypes ?? 5,
      debug: config?.debug ?? false
    }

    this.stats = {
      totalQueries: 0,
      singleTypeQueries: 0,
      multiTypeQueries: 0,
      allTypesQueries: 0,
      avgConfidence: 0
    }

    prodLog.info(
      `TypeAwareQueryPlanner initialized: thresholds single=${this.config.singleTypeThreshold}, multi=${this.config.multiTypeThreshold}`
    )
  }

  /**
   * Plan an optimized query execution strategy using semantic type inference
   *
   * @param query - Natural language query string
   * @returns Promise resolving to optimized query plan with routing strategy
   */
  async planQuery(query: string): Promise<TypeAwareQueryPlan> {
    const startTime = performance.now()

    if (!query || query.trim().length === 0) {
      return this.createAllTypesPlan(query, 'Empty query')
    }

    // Infer noun types for graph routing (nouns only, verbs not used for routing)
    const inferences = await inferNouns(query, {
      maxResults: this.config.maxMultiTypes,
      minConfidence: this.config.multiTypeThreshold
    })

    if (inferences.length === 0) {
      return this.createAllTypesPlan(query, 'No types inferred from query')
    }

    // Determine routing strategy based on inference confidence
    const plan = this.selectRoutingStrategy(query, inferences)

    // Update statistics
    this.updateStats(plan)

    const elapsed = performance.now() - startTime

    if (this.config.debug) {
      prodLog.debug(
        `Query plan: ${plan.routing} with ${plan.targetTypes.length} types (${elapsed.toFixed(2)}ms)`
      )
    }

    // Performance assertion
    if (elapsed > 10) {
      prodLog.warn(
        `Query planning slow: ${elapsed.toFixed(2)}ms (target: < 10ms)`
      )
    }

    return plan
  }

  /**
   * Select routing strategy based on semantic inference results
   */
  private selectRoutingStrategy(
    query: string,
    inferences: TypeInference[]
  ): TypeAwareQueryPlan {
    const topInference = inferences[0]

    // Strategy 1: Single-type routing (highest confidence)
    if (
      topInference.confidence >= this.config.singleTypeThreshold &&
      (inferences.length === 1 ||
        inferences[1].confidence < this.config.multiTypeThreshold)
    ) {
      return {
        originalQuery: query,
        inferredTypes: inferences,
        routing: 'single-type',
        targetTypes: [topInference.type as NounType],
        estimatedSpeedup: NOUN_TYPE_COUNT / 1,
        confidence: topInference.confidence,
        reasoning: `High confidence (${(topInference.confidence * 100).toFixed(0)}%) for single type: ${topInference.type}`
      }
    }

    // Strategy 2: Multi-type routing (moderate confidence, multiple types)
    if (topInference.confidence >= this.config.multiTypeThreshold) {
      const relevantTypes = inferences
        .filter(inf => inf.confidence >= this.config.multiTypeThreshold)
        .slice(0, this.config.maxMultiTypes)
        .map(inf => inf.type as NounType)

      const avgConfidence =
        relevantTypes.reduce((sum, type) => {
          const inf = inferences.find(i => i.type === type)
          return sum + (inf?.confidence || 0)
        }, 0) / relevantTypes.length

      return {
        originalQuery: query,
        inferredTypes: inferences,
        routing: 'multi-type',
        targetTypes: relevantTypes,
        estimatedSpeedup: NOUN_TYPE_COUNT / relevantTypes.length,
        confidence: avgConfidence,
        reasoning: `Multiple types detected with moderate confidence (avg ${(avgConfidence * 100).toFixed(0)}%): ${relevantTypes.join(', ')}`
      }
    }

    // Strategy 3: All-types fallback (low confidence)
    return this.createAllTypesPlan(
      query,
      `Low confidence (${(topInference.confidence * 100).toFixed(0)}%) - searching all types for safety`
    )
  }

  /**
   * Create an all-types plan (fallback strategy)
   */
  private createAllTypesPlan(query: string, reasoning: string): TypeAwareQueryPlan {
    return {
      originalQuery: query,
      inferredTypes: [],
      routing: 'all-types',
      targetTypes: this.getAllNounTypes(),
      estimatedSpeedup: 1.0,
      confidence: 0.0,
      reasoning
    }
  }

  /**
   * Get all noun types (for all-types routing)
   */
  private getAllNounTypes(): NounType[] {
    return [
      NounType.Person,
      NounType.Organization,
      NounType.Location,
      NounType.Thing,
      NounType.Concept,
      NounType.Event,
      NounType.Document,
      NounType.Media,
      NounType.File,
      NounType.Message,
      NounType.Content,
      NounType.Collection,
      NounType.Dataset,
      NounType.Product,
      NounType.Service,
      NounType.User,
      NounType.Task,
      NounType.Project,
      NounType.Process,
      NounType.State,
      NounType.Role,
      NounType.Topic,
      NounType.Language,
      NounType.Currency,
      NounType.Measurement,
      NounType.Hypothesis,
      NounType.Experiment,
      NounType.Contract,
      NounType.Regulation,
      NounType.Interface,
      NounType.Resource
    ]
  }

  /**
   * Update query statistics
   */
  private updateStats(plan: TypeAwareQueryPlan): void {
    this.stats.totalQueries++

    switch (plan.routing) {
      case 'single-type':
        this.stats.singleTypeQueries++
        break
      case 'multi-type':
        this.stats.multiTypeQueries++
        break
      case 'all-types':
        this.stats.allTypesQueries++
        break
    }

    // Update rolling average confidence
    this.stats.avgConfidence =
      (this.stats.avgConfidence * (this.stats.totalQueries - 1) + plan.confidence) /
      this.stats.totalQueries
  }

  /**
   * Get query statistics
   */
  getStats(): QueryStats {
    return { ...this.stats }
  }

  /**
   * Get detailed statistics report
   */
  getStatsReport(): string {
    const total = this.stats.totalQueries

    if (total === 0) {
      return 'No queries processed yet'
    }

    const singlePct = ((this.stats.singleTypeQueries / total) * 100).toFixed(1)
    const multiPct = ((this.stats.multiTypeQueries / total) * 100).toFixed(1)
    const allPct = ((this.stats.allTypesQueries / total) * 100).toFixed(1)
    const avgConf = (this.stats.avgConfidence * 100).toFixed(1)

    // Calculate weighted average speedup
    const avgSpeedup = (
      (this.stats.singleTypeQueries * 31.0 +
        this.stats.multiTypeQueries * 10.0 +
        this.stats.allTypesQueries * 1.0) /
      total
    ).toFixed(1)

    return `
Query Statistics (${total} total):
- Single-type: ${this.stats.singleTypeQueries} (${singlePct}%) - 31x speedup
- Multi-type:  ${this.stats.multiTypeQueries} (${multiPct}%) - ~10x speedup
- All-types:   ${this.stats.allTypesQueries} (${allPct}%) - 1x speedup
- Avg confidence: ${avgConf}%
- Avg speedup: ${avgSpeedup}x
`.trim()
  }

  /**
   * Reset statistics
   */
  resetStats(): void {
    this.stats = {
      totalQueries: 0,
      singleTypeQueries: 0,
      multiTypeQueries: 0,
      allTypesQueries: 0,
      avgConfidence: 0
    }
  }

  /**
   * Analyze a batch of queries to understand distribution
   *
   * Useful for optimizing thresholds and understanding usage patterns
   */
  async analyzeQueries(queries: string[]): Promise<{
    distribution: Record<QueryRoutingStrategy, number>
    avgSpeedup: number
    recommendations: string[]
  }> {
    const distribution: Record<QueryRoutingStrategy, number> = {
      'single-type': 0,
      'multi-type': 0,
      'all-types': 0
    }

    let totalSpeedup = 0

    for (const query of queries) {
      const plan = await this.planQuery(query)
      distribution[plan.routing]++
      totalSpeedup += plan.estimatedSpeedup
    }

    const avgSpeedup = totalSpeedup / queries.length

    // Generate recommendations
    const recommendations: string[] = []

    const singlePct = (distribution['single-type'] / queries.length) * 100
    const multiPct = (distribution['multi-type'] / queries.length) * 100
    const allPct = (distribution['all-types'] / queries.length) * 100

    if (allPct > 30) {
      recommendations.push(
        `High all-types usage (${allPct.toFixed(0)}%) - consider lowering multiTypeThreshold or expanding keyword dictionary`
      )
    }

    if (singlePct > 70) {
      recommendations.push(
        `High single-type usage (${singlePct.toFixed(0)}%) - excellent! Type inference is working well`
      )
    }

    if (avgSpeedup < 5) {
      recommendations.push(
        `Low average speedup (${avgSpeedup.toFixed(1)}x) - consider adjusting confidence thresholds`
      )
    } else if (avgSpeedup > 15) {
      recommendations.push(
        `Excellent average speedup (${avgSpeedup.toFixed(1)}x) - type-first routing is highly effective`
      )
    }

    return {
      distribution,
      avgSpeedup,
      recommendations
    }
  }
}

/**
 * Global singleton instance for convenience
 */
let globalPlanner: TypeAwareQueryPlanner | null = null

/**
 * Get or create the global TypeAwareQueryPlanner instance
 */
export function getQueryPlanner(config?: QueryPlannerConfig): TypeAwareQueryPlanner {
  if (!globalPlanner) {
    globalPlanner = new TypeAwareQueryPlanner(config)
  }
  return globalPlanner
}

/**
 * Convenience function to plan a query
 */
export async function planQuery(query: string, config?: QueryPlannerConfig): Promise<TypeAwareQueryPlan> {
  return getQueryPlanner(config).planQuery(query)
}
