/**
 * Relationship Confidence Scoring
 *
 * Scores the confidence of detected relationships based on multiple factors:
 * - Entity proximity in text
 * - Entity confidence scores
 * - Pattern matches
 * - Structural analysis
 *
 * PRODUCTION-READY - NO MOCKS, NO STUBS, REAL IMPLEMENTATION
 */

import { ExtractedEntity } from './entityExtractor.js'
import { VerbType } from '../types/graphTypes.js'
import { RelationEvidence } from '../types/brainy.types.js'

/**
 * Detected relationship with confidence
 */
export interface DetectedRelationship {
  sourceEntity: ExtractedEntity
  targetEntity: ExtractedEntity
  verbType: VerbType
  confidence: number
  evidence: RelationEvidence
}

/**
 * Configuration for relationship detection
 */
export interface RelationshipDetectionConfig {
  minConfidence?: number  // Minimum confidence to return (default: 0.5)
  maxDistance?: number    // Maximum token distance between entities (default: 50)
  useProximityBoost?: boolean  // Boost score based on proximity (default: true)
  usePatternMatching?: boolean  // Use verb pattern matching (default: true)
  useStructuralAnalysis?: boolean  // Analyze sentence structure (default: true)
}

/**
 * Relationship confidence scorer
 */
export class RelationshipConfidenceScorer {
  private config: Required<RelationshipDetectionConfig>

  constructor(config: RelationshipDetectionConfig = {}) {
    this.config = {
      minConfidence: config.minConfidence || 0.5,
      maxDistance: config.maxDistance || 50,
      useProximityBoost: config.useProximityBoost !== false,
      usePatternMatching: config.usePatternMatching !== false,
      useStructuralAnalysis: config.useStructuralAnalysis !== false
    }
  }

  /**
   * Score a potential relationship between two entities
   */
  scoreRelationship(
    source: ExtractedEntity,
    target: ExtractedEntity,
    verbType: VerbType,
    context: string
  ): { confidence: number, evidence: RelationEvidence } {
    let confidence = 0.5  // Base confidence

    // Evidence tracking
    const reasoningParts: string[] = []

    // Factor 1: Proximity boost (closer entities = higher confidence)
    if (this.config.useProximityBoost) {
      const proximityBoost = this.calculateProximityBoost(source, target)
      confidence += proximityBoost
      if (proximityBoost > 0) {
        reasoningParts.push(
          `Entities are close together (boost: +${proximityBoost.toFixed(2)})`
        )
      }
    }

    // Factor 2: Entity confidence boost
    const entityConfidence = (source.confidence + target.confidence) / 2
    const entityBoost = (entityConfidence - 0.5) * 0.2  // Scale to 0-0.2
    confidence *= (1 + entityBoost)
    if (entityBoost > 0) {
      reasoningParts.push(
        `High entity confidence (boost: ${entityBoost.toFixed(2)})`
      )
    }

    // Factor 3: Pattern match boost
    if (this.config.usePatternMatching) {
      const patternBoost = this.checkVerbPattern(source, target, verbType, context)
      confidence += patternBoost
      if (patternBoost > 0) {
        reasoningParts.push(
          `Matches relationship pattern (boost: +${patternBoost.toFixed(2)})`
        )
      }
    }

    // Factor 4: Structural boost (same sentence, clause, etc.)
    if (this.config.useStructuralAnalysis) {
      const structuralBoost = this.analyzeStructure(source, target, context)
      confidence += structuralBoost
      if (structuralBoost > 0) {
        reasoningParts.push(
          `Structural relationship (boost: +${structuralBoost.toFixed(2)})`
        )
      }
    }

    // Cap confidence at 1.0
    confidence = Math.min(confidence, 1.0)

    // Extract source text evidence
    const start = Math.min(source.position.start, target.position.start)
    const end = Math.max(source.position.end, target.position.end)

    const evidence: RelationEvidence = {
      sourceText: context.substring(start, end),
      position: { start, end },
      method: 'neural',
      reasoning: reasoningParts.join('; ')
    }

    return { confidence, evidence }
  }

  /**
   * Calculate proximity boost based on distance between entities
   */
  private calculateProximityBoost(
    source: ExtractedEntity,
    target: ExtractedEntity
  ): number {
    const distance = Math.abs(source.position.start - target.position.start)

    if (distance === 0) return 0  // Same position, not meaningful

    // Very close (< 20 chars): +0.2
    if (distance < 20) return 0.2

    // Close (< 50 chars): +0.1
    if (distance < 50) return 0.1

    // Medium (< 100 chars): +0.05
    if (distance < 100) return 0.05

    // Far (> 100 chars): no boost
    return 0
  }

  /**
   * Check if entities match a verb pattern
   */
  private checkVerbPattern(
    source: ExtractedEntity,
    target: ExtractedEntity,
    verbType: VerbType,
    context: string
  ): number {
    const contextBetween = this.getContextBetween(source, target, context)
    const contextLower = contextBetween.toLowerCase()

    // Verb-specific patterns
    const patterns: Record<string, string[]> = {
      [VerbType.Creates]: ['creates', 'made', 'built', 'developed', 'produces'],
      [VerbType.Owns]: ['owns', 'belongs to', 'possessed by', 'has'],
      [VerbType.Contains]: ['contains', 'includes', 'has', 'holds'],
      [VerbType.Requires]: ['requires', 'needs', 'depends on', 'relies on'],
      [VerbType.Uses]: ['uses', 'utilizes', 'employs', 'applies'],
      [VerbType.Supervises]: ['manages', 'oversees', 'supervises', 'controls'],
      [VerbType.Causes]: ['influences', 'affects', 'impacts', 'shapes', 'causes'],
      [VerbType.DependsOn]: ['depends on', 'relies on', 'based on'],
      [VerbType.Modifies]: ['modifies', 'changes', 'alters', 'updates'],
      [VerbType.References]: ['references', 'cites', 'mentions', 'refers to']
    }

    const verbPatterns = patterns[verbType] || []

    for (const pattern of verbPatterns) {
      if (contextLower.includes(pattern)) {
        return 0.2  // Strong pattern match
      }
    }

    return 0  // No pattern match
  }

  /**
   * Analyze structural relationship
   */
  private analyzeStructure(
    source: ExtractedEntity,
    target: ExtractedEntity,
    context: string
  ): number {
    const contextBetween = this.getContextBetween(source, target, context)

    // Same sentence (no sentence-ending punctuation between them)
    if (!contextBetween.match(/[.!?]/)) {
      return 0.1
    }

    // Same paragraph (single newline between them)
    if (!contextBetween.match(/\n\n/)) {
      return 0.05
    }

    return 0
  }

  /**
   * Get context text between two entities
   */
  private getContextBetween(
    source: ExtractedEntity,
    target: ExtractedEntity,
    context: string
  ): string {
    const start = Math.min(source.position.end, target.position.end)
    const end = Math.max(source.position.start, target.position.start)

    if (start >= end) return ''

    return context.substring(start, end)
  }

  /**
   * Detect relationships between a list of entities
   */
  detectRelationships(
    entities: ExtractedEntity[],
    context: string,
    verbHints?: VerbType[]
  ): DetectedRelationship[] {
    const relationships: DetectedRelationship[] = []
    const verbs = verbHints || [
      VerbType.Creates,
      VerbType.Uses,
      VerbType.Contains,
      VerbType.Requires,
      VerbType.RelatedTo
    ]

    // Check all entity pairs
    for (let i = 0; i < entities.length; i++) {
      for (let j = i + 1; j < entities.length; j++) {
        const source = entities[i]
        const target = entities[j]

        // Check distance
        const distance = Math.abs(source.position.start - target.position.start)
        if (distance > this.config.maxDistance) {
          continue  // Too far apart
        }

        // Try each verb type
        for (const verbType of verbs) {
          const { confidence, evidence } = this.scoreRelationship(
            source,
            target,
            verbType,
            context
          )

          if (confidence >= this.config.minConfidence) {
            relationships.push({
              sourceEntity: source,
              targetEntity: target,
              verbType,
              confidence,
              evidence
            })
          }
        }
      }
    }

    // Sort by confidence (highest first)
    relationships.sort((a, b) => b.confidence - a.confidence)

    return relationships
  }
}

/**
 * Convenience function to score a single relationship
 */
export function scoreRelationshipConfidence(
  source: ExtractedEntity,
  target: ExtractedEntity,
  verbType: VerbType,
  context: string,
  config?: RelationshipDetectionConfig
): { confidence: number, evidence: RelationEvidence } {
  const scorer = new RelationshipConfidenceScorer(config)
  return scorer.scoreRelationship(source, target, verbType, context)
}

/**
 * Convenience function to detect all relationships in text
 */
export function detectRelationshipsWithConfidence(
  entities: ExtractedEntity[],
  context: string,
  config?: RelationshipDetectionConfig
): DetectedRelationship[] {
  const scorer = new RelationshipConfidenceScorer(config)
  return scorer.detectRelationships(entities, context)
}
