package intelligence

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"sync"
	"time"

	slurpContext "chorus.services/bzzz/pkg/slurp/context"
)

// DefaultRAGIntegration provides comprehensive RAG system integration
type DefaultRAGIntegration struct {
	config         *EngineConfig
	httpClient     *http.Client
	queryOptimizer *QueryOptimizer
	indexManager   *IndexManager
	cacheManager   *RAGCacheManager
	fallbackEngine *FallbackEngine
	statsTracker   *RAGStatsTracker
}

// QueryOptimizer optimizes queries for better RAG retrieval
type QueryOptimizer struct {
	queryTemplates map[string]*QueryTemplate
	contextEnricher *ContextEnricher
}

// QueryTemplate defines structured queries for different use cases
type QueryTemplate struct {
	Name        string
	Template    string
	Variables   []string
	Context     map[string]interface{}
	Priority    int
	Timeout     time.Duration
}

// ContextEnricher adds contextual information to queries
type ContextEnricher struct {
	enrichmentRules []*EnrichmentRule
}

// EnrichmentRule defines how to enrich queries with context
type EnrichmentRule struct {
	Trigger     string
	Action      string
	Parameters  map[string]interface{}
	Weight      float64
	Conditions  []string
}

// IndexManager manages RAG index operations
type IndexManager struct {
	mu              sync.RWMutex
	indexedContent  map[string]*IndexedDocument
	indexingQueue   chan *IndexingRequest
	batchProcessor  *BatchProcessor
	stats           *IndexStats
}

// IndexedDocument represents a document in the RAG index
type IndexedDocument struct {
	ID          string                 `json:"id"`
	Content     string                 `json:"content"`
	Metadata    map[string]interface{} `json:"metadata"`
	Embeddings  []float64              `json:"embeddings,omitempty"`
	IndexedAt   time.Time              `json:"indexed_at"`
	UpdatedAt   time.Time              `json:"updated_at"`
	Version     int                    `json:"version"`
	Tags        []string               `json:"tags"`
	Language    string                 `json:"language"`
	Size        int64                  `json:"size"`
}

// IndexingRequest represents a request to index content
type IndexingRequest struct {
	DocumentID string
	Content    string
	Metadata   map[string]interface{}
	Priority   int
	Callback   func(error)
}

// BatchProcessor handles batch indexing operations
type BatchProcessor struct {
	batchSize     int
	batchTimeout  time.Duration
	pendingBatch  []*IndexingRequest
	mu            sync.Mutex
	lastFlush     time.Time
}

// IndexStats tracks indexing statistics
type IndexStats struct {
	TotalDocuments   int64     `json:"total_documents"`
	IndexedToday     int64     `json:"indexed_today"`
	IndexingErrors   int64     `json:"indexing_errors"`
	AverageIndexTime time.Duration `json:"average_index_time"`
	LastIndexTime    time.Time `json:"last_index_time"`
	IndexSize        int64     `json:"index_size"`
}

// RAGCacheManager manages caching for RAG responses
type RAGCacheManager struct {
	cache         sync.Map
	cacheTTL      time.Duration
	maxCacheSize  int
	currentSize   int
	mu            sync.RWMutex
	cleanupTicker *time.Ticker
}

// RAGCacheEntry represents a cached RAG response
type RAGCacheEntry struct {
	Query       string      `json:"query"`
	Response    *RAGResponse `json:"response"`
	CreatedAt   time.Time   `json:"created_at"`
	ExpiresAt   time.Time   `json:"expires_at"`
	AccessCount int         `json:"access_count"`
	LastAccess  time.Time   `json:"last_access"`
	Size        int         `json:"size"`
}

// FallbackEngine provides fallback when RAG is unavailable
type FallbackEngine struct {
	localKnowledge *LocalKnowledgeBase
	ruleEngine     *RuleBasedEngine
	templateEngine *TemplateEngine
}

// LocalKnowledgeBase contains local knowledge for fallback
type LocalKnowledgeBase struct {
	knowledgeBase map[string]*KnowledgeEntry
	patterns      []*KnowledgePattern
	mu            sync.RWMutex
}

// KnowledgeEntry represents a local knowledge entry
type KnowledgeEntry struct {
	Topic       string                 `json:"topic"`
	Content     string                 `json:"content"`
	Keywords    []string               `json:"keywords"`
	Confidence  float64                `json:"confidence"`
	Source      string                 `json:"source"`
	Tags        []string               `json:"tags"`
	Metadata    map[string]interface{} `json:"metadata"`
	CreatedAt   time.Time              `json:"created_at"`
	UpdatedAt   time.Time              `json:"updated_at"`
}

// KnowledgePattern represents a pattern in local knowledge
type KnowledgePattern struct {
	Pattern     string    `json:"pattern"`
	Response    string    `json:"response"`
	Confidence  float64   `json:"confidence"`
	Examples    []string  `json:"examples"`
	Category    string    `json:"category"`
}

// RuleBasedEngine provides rule-based fallback responses
type RuleBasedEngine struct {
	rules []*ResponseRule
}

// ResponseRule defines a rule for generating responses
type ResponseRule struct {
	Condition   string    `json:"condition"`
	Response    string    `json:"response"`
	Priority    int       `json:"priority"`
	Confidence  float64   `json:"confidence"`
	Tags        []string  `json:"tags"`
}

// TemplateEngine generates responses from templates
type TemplateEngine struct {
	templates map[string]*ResponseTemplate
}

// ResponseTemplate defines a response template
type ResponseTemplate struct {
	Name        string                 `json:"name"`
	Template    string                 `json:"template"`
	Variables   []string               `json:"variables"`
	Category    string                 `json:"category"`
	Confidence  float64                `json:"confidence"`
	Metadata    map[string]interface{} `json:"metadata"`
}

// RAGStatsTracker tracks RAG performance statistics
type RAGStatsTracker struct {
	mu                sync.RWMutex
	totalQueries      int64
	successfulQueries int64
	failedQueries     int64
	cacheHits         int64
	cacheMisses       int64
	averageLatency    time.Duration
	fallbackUsed      int64
	lastReset         time.Time
}

// NewDefaultRAGIntegration creates a new RAG integration
func NewDefaultRAGIntegration(config *EngineConfig) *DefaultRAGIntegration {
	integration := &DefaultRAGIntegration{
		config: config,
		httpClient: &http.Client{
			Timeout: config.RAGTimeout,
			Transport: &http.Transport{
				MaxIdleConns:        10,
				MaxIdleConnsPerHost: 5,
				IdleConnTimeout:     30 * time.Second,
			},
		},
		queryOptimizer: NewQueryOptimizer(),
		indexManager:   NewIndexManager(),
		cacheManager:   NewRAGCacheManager(config.CacheTTL),
		fallbackEngine: NewFallbackEngine(),
		statsTracker:   NewRAGStatsTracker(),
	}

	// Start background processes
	go integration.indexManager.startBatchProcessor()
	go integration.cacheManager.startCleanupRoutine()

	return integration
}

// NewQueryOptimizer creates a query optimizer
func NewQueryOptimizer() *QueryOptimizer {
	optimizer := &QueryOptimizer{
		queryTemplates:  make(map[string]*QueryTemplate),
		contextEnricher: NewContextEnricher(),
	}

	// Define standard query templates
	templates := []*QueryTemplate{
		{
			Name:     "code_analysis",
			Template: "Analyze the {{language}} code in {{file_path}}. Focus on {{focus_areas}}. Consider {{context}}.",
			Variables: []string{"language", "file_path", "focus_areas", "context"},
			Priority: 1,
			Timeout:  30 * time.Second,
		},
		{
			Name:     "architecture_advice",
			Template: "Provide architectural guidance for {{component_type}} in {{project_context}}. Consider {{constraints}} and {{goals}}.",
			Variables: []string{"component_type", "project_context", "constraints", "goals"},
			Priority: 2,
			Timeout:  45 * time.Second,
		},
		{
			Name:     "best_practices",
			Template: "What are the best practices for {{technology}} in {{use_case}}? Consider {{requirements}}.",
			Variables: []string{"technology", "use_case", "requirements"},
			Priority: 1,
			Timeout:  20 * time.Second,
		},
		{
			Name:     "pattern_recommendation",
			Template: "Recommend design patterns for {{problem_description}} using {{technologies}}. Context: {{project_context}}.",
			Variables: []string{"problem_description", "technologies", "project_context"},
			Priority: 2,
			Timeout:  35 * time.Second,
		},
	}

	for _, template := range templates {
		optimizer.queryTemplates[template.Name] = template
	}

	return optimizer
}

// NewContextEnricher creates a context enricher
func NewContextEnricher() *ContextEnricher {
	enricher := &ContextEnricher{
		enrichmentRules: []*EnrichmentRule{},
	}

	// Define enrichment rules
	rules := []*EnrichmentRule{
		{
			Trigger:    "code_analysis",
			Action:     "add_language_context",
			Parameters: map[string]interface{}{"depth": "detailed"},
			Weight:     0.8,
			Conditions: []string{"has_language", "has_file_path"},
		},
		{
			Trigger:    "architecture",
			Action:     "add_project_context",
			Parameters: map[string]interface{}{"scope": "system_wide"},
			Weight:     0.9,
			Conditions: []string{"has_project_info"},
		},
		{
			Trigger:    "performance",
			Action:     "add_performance_context",
			Parameters: map[string]interface{}{"metrics": "standard"},
			Weight:     0.7,
			Conditions: []string{"has_performance_data"},
		},
	}

	enricher.enrichmentRules = rules
	return enricher
}

// NewIndexManager creates an index manager
func NewIndexManager() *IndexManager {
	return &IndexManager{
		indexedContent: make(map[string]*IndexedDocument),
		indexingQueue:  make(chan *IndexingRequest, 1000),
		batchProcessor: &BatchProcessor{
			batchSize:    10,
			batchTimeout: 30 * time.Second,
			lastFlush:    time.Now(),
		},
		stats: &IndexStats{
			LastIndexTime: time.Now(),
		},
	}
}

// NewRAGCacheManager creates a cache manager
func NewRAGCacheManager(ttl time.Duration) *RAGCacheManager {
	manager := &RAGCacheManager{
		cacheTTL:     ttl,
		maxCacheSize: 1000, // Maximum cached entries
	}

	return manager
}

// NewFallbackEngine creates a fallback engine
func NewFallbackEngine() *FallbackEngine {
	return &FallbackEngine{
		localKnowledge: NewLocalKnowledgeBase(),
		ruleEngine:     NewRuleBasedEngine(),
		templateEngine: NewTemplateEngine(),
	}
}

// NewLocalKnowledgeBase creates a local knowledge base
func NewLocalKnowledgeBase() *LocalKnowledgeBase {
	kb := &LocalKnowledgeBase{
		knowledgeBase: make(map[string]*KnowledgeEntry),
		patterns:      []*KnowledgePattern{},
	}

	// Load default knowledge entries
	kb.loadDefaultKnowledge()
	return kb
}

// NewRuleBasedEngine creates a rule-based engine
func NewRuleBasedEngine() *RuleBasedEngine {
	engine := &RuleBasedEngine{
		rules: []*ResponseRule{},
	}

	// Load default rules
	engine.loadDefaultRules()
	return engine
}

// NewTemplateEngine creates a template engine
func NewTemplateEngine() *TemplateEngine {
	engine := &TemplateEngine{
		templates: make(map[string]*ResponseTemplate),
	}

	// Load default templates
	engine.loadDefaultTemplates()
	return engine
}

// NewRAGStatsTracker creates a stats tracker
func NewRAGStatsTracker() *RAGStatsTracker {
	return &RAGStatsTracker{
		lastReset: time.Now(),
	}
}

// Query queries the RAG system for relevant information
func (ri *DefaultRAGIntegration) Query(ctx context.Context, query string, context map[string]interface{}) (*RAGResponse, error) {
	start := time.Now()
	ri.statsTracker.recordQuery()

	// Check cache first
	if cached := ri.cacheManager.get(query); cached != nil {
		ri.statsTracker.recordCacheHit()
		return cached.Response, nil
	}
	ri.statsTracker.recordCacheMiss()

	// Optimize query
	optimizedQuery := ri.queryOptimizer.optimizeQuery(query, context)

	// Try RAG system
	response, err := ri.queryRAGSystem(ctx, optimizedQuery)
	if err != nil {
		// Fallback to local knowledge
		ri.statsTracker.recordFallback()
		response, err = ri.fallbackEngine.generateResponse(ctx, query, context)
		if err != nil {
			ri.statsTracker.recordFailure()
			return nil, fmt.Errorf("both RAG and fallback failed: %w", err)
		}
	}

	// Cache successful response
	ri.cacheManager.put(query, response)
	
	// Update stats
	ri.statsTracker.recordSuccess(time.Since(start))

	return response, nil
}

// EnhanceContext enhances context using RAG knowledge
func (ri *DefaultRAGIntegration) EnhanceContext(ctx context.Context, node *slurpContext.ContextNode) (*slurpContext.ContextNode, error) {
	// Create enhancement query
	query := ri.buildEnhancementQuery(node)
	queryContext := ri.buildQueryContext(node)

	// Query RAG system
	response, err := ri.Query(ctx, query, queryContext)
	if err != nil {
		return node, fmt.Errorf("failed to enhance context: %w", err)
	}

	// Apply enhancements
	enhanced := ri.applyEnhancements(node, response)
	return enhanced, nil
}

// IndexContent indexes content for RAG retrieval
func (ri *DefaultRAGIntegration) IndexContent(ctx context.Context, content string, metadata map[string]interface{}) error {
	request := &IndexingRequest{
		DocumentID: ri.generateDocumentID(content, metadata),
		Content:    content,
		Metadata:   metadata,
		Priority:   1,
	}

	select {
	case ri.indexManager.indexingQueue <- request:
		return nil
	default:
		return fmt.Errorf("indexing queue is full")
	}
}

// SearchSimilar searches for similar content in RAG system
func (ri *DefaultRAGIntegration) SearchSimilar(ctx context.Context, content string, limit int) ([]*RAGResult, error) {
	// Build similarity search query
	query := fmt.Sprintf("Find similar content to: %s", content)
	
	// Query RAG system for similar content
	response, err := ri.Query(ctx, query, map[string]interface{}{
		"search_type": "similarity",
		"limit":       limit,
		"content":     content,
	})
	
	if err != nil {
		return nil, fmt.Errorf("similarity search failed: %w", err)
	}

	// Convert response to results
	results := ri.convertToRAGResults(response, limit)
	return results, nil
}

// UpdateIndex updates RAG index with new content
func (ri *DefaultRAGIntegration) UpdateIndex(ctx context.Context, updates []*RAGUpdate) error {
	for _, update := range updates {
		metadata := update.Metadata
		if metadata == nil {
			metadata = make(map[string]interface{})
		}
		metadata["operation"] = update.Operation

		err := ri.IndexContent(ctx, update.Content, metadata)
		if err != nil {
			return fmt.Errorf("failed to update index for document %s: %w", update.ID, err)
		}
	}

	return nil
}

// GetRAGStats returns RAG system statistics
func (ri *DefaultRAGIntegration) GetRAGStats(ctx context.Context) (*RAGStatistics, error) {
	stats := ri.statsTracker.getStats()
	indexStats := ri.indexManager.getStats()

	return &RAGStatistics{
		TotalDocuments:   indexStats.TotalDocuments,
		TotalQueries:     stats.totalQueries,
		AverageQueryTime: stats.averageLatency,
		IndexSize:        indexStats.IndexSize,
		LastIndexUpdate:  indexStats.LastIndexTime,
		ErrorRate:        ri.calculateErrorRate(stats),
	}, nil
}

// Helper methods

func (ri *DefaultRAGIntegration) queryRAGSystem(ctx context.Context, query string) (*RAGResponse, error) {
	if ri.config.RAGEndpoint == "" {
		return nil, fmt.Errorf("RAG endpoint not configured")
	}

	// Prepare request
	requestBody := map[string]interface{}{
		"query":   query,
		"timeout": ri.config.RAGTimeout.Seconds(),
	}

	jsonBody, err := json.Marshal(requestBody)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	// Create HTTP request
	req, err := http.NewRequestWithContext(ctx, "POST", ri.config.RAGEndpoint, bytes.NewBuffer(jsonBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")

	// Execute request
	resp, err := ri.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("RAG request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("RAG request failed with status: %d", resp.StatusCode)
	}

	// Parse response
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response: %w", err)
	}

	var ragResponse RAGResponse
	if err := json.Unmarshal(body, &ragResponse); err != nil {
		return nil, fmt.Errorf("failed to parse response: %w", err)
	}

	ragResponse.ProcessedAt = time.Now()
	return &ragResponse, nil
}

func (qo *QueryOptimizer) optimizeQuery(query string, context map[string]interface{}) string {
	// Determine query type
	queryType := qo.determineQueryType(query, context)
	
	// Get appropriate template
	template, exists := qo.queryTemplates[queryType]
	if !exists {
		return query // Return original if no template
	}

	// Apply template
	optimizedQuery := qo.applyTemplate(template, query, context)
	
	// Enrich with context
	enrichedQuery := qo.contextEnricher.enrichQuery(optimizedQuery, context)
	
	return enrichedQuery
}

func (qo *QueryOptimizer) determineQueryType(query string, context map[string]interface{}) string {
	lowerQuery := strings.ToLower(query)
	
	// Simple keyword matching for query type determination
	if strings.Contains(lowerQuery, "analyze") || strings.Contains(lowerQuery, "code") {
		return "code_analysis"
	}
	if strings.Contains(lowerQuery, "architecture") || strings.Contains(lowerQuery, "design") {
		return "architecture_advice"
	}
	if strings.Contains(lowerQuery, "best practice") || strings.Contains(lowerQuery, "recommendation") {
		return "best_practices"
	}
	if strings.Contains(lowerQuery, "pattern") {
		return "pattern_recommendation"
	}
	
	return "code_analysis" // Default
}

func (qo *QueryOptimizer) applyTemplate(template *QueryTemplate, query string, context map[string]interface{}) string {
	result := template.Template
	
	// Replace template variables with context values
	for _, variable := range template.Variables {
		placeholder := fmt.Sprintf("{{%s}}", variable)
		if value, exists := context[variable]; exists {
			result = strings.ReplaceAll(result, placeholder, fmt.Sprintf("%v", value))
		} else {
			// Provide reasonable defaults
			switch variable {
			case "language":
				if lang, ok := context["language"]; ok {
					result = strings.ReplaceAll(result, placeholder, fmt.Sprintf("%v", lang))
				} else {
					result = strings.ReplaceAll(result, placeholder, "unknown")
				}
			case "file_path":
				if path, ok := context["file_path"]; ok {
					result = strings.ReplaceAll(result, placeholder, fmt.Sprintf("%v", path))
				} else {
					result = strings.ReplaceAll(result, placeholder, "current file")
				}
			default:
				result = strings.ReplaceAll(result, placeholder, query)
			}
		}
	}
	
	return result
}

func (ce *ContextEnricher) enrichQuery(query string, context map[string]interface{}) string {
	enriched := query
	
	// Apply enrichment rules
	for _, rule := range ce.enrichmentRules {
		if ce.shouldApplyRule(rule, context) {
			enriched = ce.applyEnrichmentRule(enriched, rule, context)
		}
	}
	
	return enriched
}

func (ce *ContextEnricher) shouldApplyRule(rule *EnrichmentRule, context map[string]interface{}) bool {
	for _, condition := range rule.Conditions {
		switch condition {
		case "has_language":
			if _, exists := context["language"]; !exists {
				return false
			}
		case "has_file_path":
			if _, exists := context["file_path"]; !exists {
				return false
			}
		case "has_project_info":
			if _, exists := context["project"]; !exists {
				return false
			}
		}
	}
	return true
}

func (ce *ContextEnricher) applyEnrichmentRule(query string, rule *EnrichmentRule, context map[string]interface{}) string {
	switch rule.Action {
	case "add_language_context":
		if lang, exists := context["language"]; exists {
			return fmt.Sprintf("%s Consider %s language-specific patterns and idioms.", query, lang)
		}
	case "add_project_context":
		if project, exists := context["project"]; exists {
			return fmt.Sprintf("%s In the context of project %v.", query, project)
		}
	case "add_performance_context":
		return fmt.Sprintf("%s Focus on performance implications and optimization opportunities.", query)
	}
	return query
}

func (ri *DefaultRAGIntegration) buildEnhancementQuery(node *slurpContext.ContextNode) string {
	return fmt.Sprintf("Provide additional insights for %s: %s. Technologies: %s", 
		node.Purpose, node.Summary, strings.Join(node.Technologies, ", "))
}

func (ri *DefaultRAGIntegration) buildQueryContext(node *slurpContext.ContextNode) map[string]interface{} {
	return map[string]interface{}{
		"file_path":    node.Path,
		"purpose":      node.Purpose,
		"technologies": node.Technologies,
		"tags":         node.Tags,
		"summary":      node.Summary,
	}
}

func (ri *DefaultRAGIntegration) applyEnhancements(node *slurpContext.ContextNode, response *RAGResponse) *slurpContext.ContextNode {
	enhanced := node.Clone()
	
	// Add RAG insights
	if response.Confidence >= ri.config.MinConfidenceThreshold {
		enhanced.Insights = append(enhanced.Insights, fmt.Sprintf("RAG: %s", response.Answer))
		enhanced.RAGConfidence = response.Confidence
		
		// Add metadata
		if enhanced.Metadata == nil {
			enhanced.Metadata = make(map[string]interface{})
		}
		enhanced.Metadata["rag_enhanced"] = true
		enhanced.Metadata["rag_sources"] = response.Sources
	}
	
	return enhanced
}

func (ri *DefaultRAGIntegration) generateDocumentID(content string, metadata map[string]interface{}) string {
	// Simple hash-based ID generation
	hash := fmt.Sprintf("%x", []byte(content))
	if len(hash) > 16 {
		hash = hash[:16]
	}
	return fmt.Sprintf("doc_%s_%d", hash, time.Now().Unix())
}

func (ri *DefaultRAGIntegration) convertToRAGResults(response *RAGResponse, limit int) []*RAGResult {
	results := []*RAGResult{}
	
	// Convert sources to results
	for i, source := range response.Sources {
		if i >= limit {
			break
		}
		
		result := &RAGResult{
			ID:         source.ID,
			Content:    source.Content,
			Score:      source.Score,
			Metadata:   source.Metadata,
			Highlights: []string{}, // Would be populated by actual RAG system
		}
		results = append(results, result)
	}
	
	return results
}

func (ri *DefaultRAGIntegration) calculateErrorRate(stats *RAGStatsTracker) float64 {
	if stats.totalQueries == 0 {
		return 0.0
	}
	return float64(stats.failedQueries) / float64(stats.totalQueries)
}

// Cache management methods

func (cm *RAGCacheManager) get(query string) *RAGCacheEntry {
	if value, ok := cm.cache.Load(query); ok {
		if entry, ok := value.(*RAGCacheEntry); ok {
			if time.Now().Before(entry.ExpiresAt) {
				entry.AccessCount++
				entry.LastAccess = time.Now()
				return entry
			}
			// Entry expired, remove it
			cm.cache.Delete(query)
		}
	}
	return nil
}

func (cm *RAGCacheManager) put(query string, response *RAGResponse) {
	entry := &RAGCacheEntry{
		Query:       query,
		Response:    response,
		CreatedAt:   time.Now(),
		ExpiresAt:   time.Now().Add(cm.cacheTTL),
		AccessCount: 1,
		LastAccess:  time.Now(),
		Size:        len(query) + len(response.Answer),
	}
	
	cm.mu.Lock()
	if cm.currentSize >= cm.maxCacheSize {
		cm.evictOldest()
	}
	cm.currentSize++
	cm.mu.Unlock()
	
	cm.cache.Store(query, entry)
}

func (cm *RAGCacheManager) evictOldest() {
	// Simple LRU eviction
	var oldestKey interface{}
	var oldestTime time.Time = time.Now()
	
	cm.cache.Range(func(key, value interface{}) bool {
		if entry, ok := value.(*RAGCacheEntry); ok {
			if entry.LastAccess.Before(oldestTime) {
				oldestTime = entry.LastAccess
				oldestKey = key
			}
		}
		return true
	})
	
	if oldestKey != nil {
		cm.cache.Delete(oldestKey)
		cm.currentSize--
	}
}

func (cm *RAGCacheManager) startCleanupRoutine() {
	cm.cleanupTicker = time.NewTicker(10 * time.Minute)
	
	for range cm.cleanupTicker.C {
		cm.cleanup()
	}
}

func (cm *RAGCacheManager) cleanup() {
	now := time.Now()
	keysToDelete := []interface{}{}
	
	cm.cache.Range(func(key, value interface{}) bool {
		if entry, ok := value.(*RAGCacheEntry); ok {
			if now.After(entry.ExpiresAt) {
				keysToDelete = append(keysToDelete, key)
			}
		}
		return true
	})
	
	cm.mu.Lock()
	for _, key := range keysToDelete {
		cm.cache.Delete(key)
		cm.currentSize--
	}
	cm.mu.Unlock()
}

// Fallback engine methods

func (fe *FallbackEngine) generateResponse(ctx context.Context, query string, context map[string]interface{}) (*RAGResponse, error) {
	// Try local knowledge base first
	if response := fe.localKnowledge.search(query); response != nil {
		return response, nil
	}
	
	// Try rule-based engine
	if response := fe.ruleEngine.generateResponse(query, context); response != nil {
		return response, nil
	}
	
	// Try template engine
	if response := fe.templateEngine.generateResponse(query, context); response != nil {
		return response, nil
	}
	
	// Return generic fallback
	return &RAGResponse{
		Query:       query,
		Answer:      "I don't have specific information about this topic in my knowledge base.",
		Sources:     []*RAGSource{},
		Confidence:  0.1,
		Context:     context,
		ProcessedAt: time.Now(),
	}, nil
}

// Additional implementation methods would continue here...
// For brevity, I'm showing the key structure and primary methods.
// In a complete implementation, all the helper methods for knowledge base loading,
// rule processing, template rendering, stats tracking, etc. would be included.

func (kb *LocalKnowledgeBase) loadDefaultKnowledge() {
	// Load default knowledge entries
	entries := []*KnowledgeEntry{
		{
			Topic:      "Go Best Practices",
			Content:    "Use clear variable names, handle errors properly, follow Go conventions for package organization.",
			Keywords:   []string{"go", "golang", "best practices", "conventions"},
			Confidence: 0.8,
			Source:     "built-in",
			Tags:       []string{"go", "best-practices"},
			CreatedAt:  time.Now(),
		},
		{
			Topic:      "JavaScript Patterns",
			Content:    "Use modern ES6+ features, avoid callback hell with async/await, follow modular design patterns.",
			Keywords:   []string{"javascript", "patterns", "es6", "async"},
			Confidence: 0.8,
			Source:     "built-in",
			Tags:       []string{"javascript", "patterns"},
			CreatedAt:  time.Now(),
		},
	}
	
	for _, entry := range entries {
		kb.knowledgeBase[entry.Topic] = entry
	}
}

func (kb *LocalKnowledgeBase) search(query string) *RAGResponse {
	lowerQuery := strings.ToLower(query)
	
	// Simple keyword matching
	for _, entry := range kb.knowledgeBase {
		for _, keyword := range entry.Keywords {
			if strings.Contains(lowerQuery, strings.ToLower(keyword)) {
				return &RAGResponse{
					Query:      query,
					Answer:     entry.Content,
					Sources:    []*RAGSource{{ID: entry.Topic, Title: entry.Topic, Content: entry.Content, Score: entry.Confidence}},
					Confidence: entry.Confidence,
					Context:    map[string]interface{}{"source": "local_knowledge"},
					ProcessedAt: time.Now(),
				}
			}
		}
	}
	
	return nil
}

func (re *RuleBasedEngine) loadDefaultRules() {
	rules := []*ResponseRule{
		{
			Condition:  "contains:error handling",
			Response:   "Always check for errors and handle them appropriately. Use proper error wrapping and logging.",
			Priority:   1,
			Confidence: 0.7,
			Tags:       []string{"error-handling", "best-practices"},
		},
		{
			Condition:  "contains:performance",
			Response:   "Consider using profiling tools, optimize algorithms, and avoid premature optimization.",
			Priority:   2,
			Confidence: 0.6,
			Tags:       []string{"performance", "optimization"},
		},
	}
	
	re.rules = rules
}

func (re *RuleBasedEngine) generateResponse(query string, context map[string]interface{}) *RAGResponse {
	lowerQuery := strings.ToLower(query)
	
	for _, rule := range re.rules {
		if re.matchesCondition(lowerQuery, rule.Condition) {
			return &RAGResponse{
				Query:      query,
				Answer:     rule.Response,
				Sources:    []*RAGSource{{ID: "rule", Title: "Rule-based response", Content: rule.Response, Score: rule.Confidence}},
				Confidence: rule.Confidence,
				Context:    map[string]interface{}{"source": "rule_engine", "rule": rule.Condition},
				ProcessedAt: time.Now(),
			}
		}
	}
	
	return nil
}

func (re *RuleBasedEngine) matchesCondition(query, condition string) bool {
	if strings.HasPrefix(condition, "contains:") {
		keyword := strings.TrimPrefix(condition, "contains:")
		return strings.Contains(query, keyword)
	}
	return false
}

func (te *TemplateEngine) loadDefaultTemplates() {
	templates := []*ResponseTemplate{
		{
			Name:       "generic_advice",
			Template:   "For {{topic}}, consider following established best practices and consulting relevant documentation.",
			Variables:  []string{"topic"},
			Category:   "general",
			Confidence: 0.4,
		},
	}
	
	for _, template := range templates {
		te.templates[template.Name] = template
	}
}

func (te *TemplateEngine) generateResponse(query string, context map[string]interface{}) *RAGResponse {
	// Simple template matching
	if template, exists := te.templates["generic_advice"]; exists {
		response := strings.ReplaceAll(template.Template, "{{topic}}", query)
		
		return &RAGResponse{
			Query:      query,
			Answer:     response,
			Sources:    []*RAGSource{{ID: "template", Title: "Template response", Content: response, Score: template.Confidence}},
			Confidence: template.Confidence,
			Context:    map[string]interface{}{"source": "template_engine", "template": template.Name},
			ProcessedAt: time.Now(),
		}
	}
	
	return nil
}

// Stats tracking methods
func (st *RAGStatsTracker) recordQuery() {
	st.mu.Lock()
	defer st.mu.Unlock()
	st.totalQueries++
}

func (st *RAGStatsTracker) recordSuccess(latency time.Duration) {
	st.mu.Lock()
	defer st.mu.Unlock()
	st.successfulQueries++
	
	// Update average latency
	if st.totalQueries == 1 {
		st.averageLatency = latency
	} else {
		st.averageLatency = time.Duration(
			(int64(st.averageLatency)*(st.totalQueries-1) + int64(latency)) / st.totalQueries,
		)
	}
}

func (st *RAGStatsTracker) recordFailure() {
	st.mu.Lock()
	defer st.mu.Unlock()
	st.failedQueries++
}

func (st *RAGStatsTracker) recordCacheHit() {
	st.mu.Lock()
	defer st.mu.Unlock()
	st.cacheHits++
}

func (st *RAGStatsTracker) recordCacheMiss() {
	st.mu.Lock()
	defer st.mu.Unlock()
	st.cacheMisses++
}

func (st *RAGStatsTracker) recordFallback() {
	st.mu.Lock()
	defer st.mu.Unlock()
	st.fallbackUsed++
}

func (st *RAGStatsTracker) getStats() *RAGStatsTracker {
	st.mu.RLock()
	defer st.mu.RUnlock()
	return &RAGStatsTracker{
		totalQueries:      st.totalQueries,
		successfulQueries: st.successfulQueries,
		failedQueries:     st.failedQueries,
		cacheHits:         st.cacheHits,
		cacheMisses:       st.cacheMisses,
		averageLatency:    st.averageLatency,
		fallbackUsed:      st.fallbackUsed,
		lastReset:         st.lastReset,
	}
}

// Index management methods
func (im *IndexManager) startBatchProcessor() {
	ticker := time.NewTicker(im.batchProcessor.batchTimeout)
	defer ticker.Stop()
	
	for {
		select {
		case request := <-im.indexingQueue:
			im.batchProcessor.mu.Lock()
			im.batchProcessor.pendingBatch = append(im.batchProcessor.pendingBatch, request)
			shouldFlush := len(im.batchProcessor.pendingBatch) >= im.batchProcessor.batchSize
			im.batchProcessor.mu.Unlock()
			
			if shouldFlush {
				im.processBatch()
			}
			
		case <-ticker.C:
			im.processBatch()
		}
	}
}

func (im *IndexManager) processBatch() {
	im.batchProcessor.mu.Lock()
	batch := im.batchProcessor.pendingBatch
	im.batchProcessor.pendingBatch = []*IndexingRequest{}
	im.batchProcessor.lastFlush = time.Now()
	im.batchProcessor.mu.Unlock()
	
	if len(batch) == 0 {
		return
	}
	
	// Process batch
	for _, request := range batch {
		err := im.indexDocument(request)
		if request.Callback != nil {
			request.Callback(err)
		}
	}
}

func (im *IndexManager) indexDocument(request *IndexingRequest) error {
	im.mu.Lock()
	defer im.mu.Unlock()
	
	doc := &IndexedDocument{
		ID:        request.DocumentID,
		Content:   request.Content,
		Metadata:  request.Metadata,
		IndexedAt: time.Now(),
		UpdatedAt: time.Now(),
		Version:   1,
		Size:      int64(len(request.Content)),
	}
	
	// Extract language if available
	if lang, exists := request.Metadata["language"]; exists {
		doc.Language = fmt.Sprintf("%v", lang)
	}
	
	// Extract tags if available
	if tags, exists := request.Metadata["tags"]; exists {
		if tagSlice, ok := tags.([]string); ok {
			doc.Tags = tagSlice
		}
	}
	
	im.indexedContent[request.DocumentID] = doc
	im.stats.TotalDocuments++
	im.stats.LastIndexTime = time.Now()
	
	return nil
}

func (im *IndexManager) getStats() *IndexStats {
	im.mu.RLock()
	defer im.mu.RUnlock()
	
	totalSize := int64(0)
	for _, doc := range im.indexedContent {
		totalSize += doc.Size
	}
	
	return &IndexStats{
		TotalDocuments: im.stats.TotalDocuments,
		IndexedToday:   im.stats.IndexedToday,
		IndexingErrors: im.stats.IndexingErrors,
		LastIndexTime:  im.stats.LastIndexTime,
		IndexSize:      totalSize,
	}
}

// NoOpRAGIntegration provides a no-op implementation when RAG is disabled
type NoOpRAGIntegration struct{}

func NewNoOpRAGIntegration() *NoOpRAGIntegration {
	return &NoOpRAGIntegration{}
}

func (nri *NoOpRAGIntegration) Query(ctx context.Context, query string, context map[string]interface{}) (*RAGResponse, error) {
	return &RAGResponse{
		Query:      query,
		Answer:     "RAG integration is disabled",
		Sources:    []*RAGSource{},
		Confidence: 0.0,
		Context:    context,
		ProcessedAt: time.Now(),
	}, nil
}

func (nri *NoOpRAGIntegration) EnhanceContext(ctx context.Context, node *slurpContext.ContextNode) (*slurpContext.ContextNode, error) {
	return node, nil
}

func (nri *NoOpRAGIntegration) IndexContent(ctx context.Context, content string, metadata map[string]interface{}) error {
	return nil
}

func (nri *NoOpRAGIntegration) SearchSimilar(ctx context.Context, content string, limit int) ([]*RAGResult, error) {
	return []*RAGResult{}, nil
}

func (nri *NoOpRAGIntegration) UpdateIndex(ctx context.Context, updates []*RAGUpdate) error {
	return nil
}

func (nri *NoOpRAGIntegration) GetRAGStats(ctx context.Context) (*RAGStatistics, error) {
	return &RAGStatistics{}, nil
}