/**
 * Runtime Type Inference from actual API responses
 */

import type { TypeDescriptor } from './type-descriptor.js'
import { inferTypeDescriptor } from './type-descriptor.js'

// Runtime type inference from actual responses
export class RuntimeTypeInference {
  private samples = new Map<string, any[]>()
  private confidence = new Map<string, number>()
  
  addSample(endpoint: string, data: any): void {
    if (!this.samples.has(endpoint)) {
      this.samples.set(endpoint, [])
    }
    
    const samples = this.samples.get(endpoint)!
    samples.push(data)
    
    // Keep only last 10 samples for inference
    if (samples.length > 10) {
      samples.shift()
    }
    
    this.updateConfidence(endpoint)
  }
  
  inferType(endpoint: string): TypeDescriptor | undefined {
    const samples = this.samples.get(endpoint)
    if (!samples || samples.length === 0) return undefined
    
    // Use the most recent sample as base, but validate against all samples
    const latestSample = samples[samples.length - 1]
    return inferTypeDescriptor(latestSample, samples)
  }
  
  private updateConfidence(endpoint: string): void {
    const samples = this.samples.get(endpoint)!
    const consistency = this.calculateConsistency(samples)
    this.confidence.set(endpoint, consistency)
  }
  
  private calculateConsistency(samples: any[]): number {
    if (samples.length < 2) return 0.5
    
    // Compare structure consistency across samples
    let matches = 0
    let total = 0
    
    for (let i = 0; i < samples.length - 1; i++) {
      const similarity = this.calculateSimilarity(samples[i], samples[i + 1])
      matches += similarity
      total += 1
    }
    
    return total > 0 ? matches / total : 0.5
  }
  
  private calculateSimilarity(a: any, b: any): number {
    if (typeof a !== typeof b) return 0
    if (a === null && b === null) return 1
    if (Array.isArray(a) && Array.isArray(b)) return 0.8 // Arrays are similar if both arrays
    
    if (typeof a === 'object' && typeof b === 'object') {
      const keysA = Object.keys(a)
      const keysB = Object.keys(b)
      const commonKeys = keysA.filter(key => keysB.includes(key))
      
      if (keysA.length === 0 && keysB.length === 0) return 1
      return commonKeys.length / Math.max(keysA.length, keysB.length)
    }
    
    return 1 // Primitives of same type are similar
  }
  
  getConfidence(endpoint: string): number {
    return this.confidence.get(endpoint) || 0
  }
}