//! Real integration with ToolRegistry
//!
//! Extends ToolRegistry with improvement capabilities:
//! - Tool effectiveness tracking
//! - Intelligent tool selection based on patterns
//! - Result caching and optimization (migrated to UnifiedCache)
//! - Observability integration

use crate::cache::{CacheKey, DEFAULT_CACHE_TTL, EvictionPolicy, UnifiedCache};
use crate::tools::{
    improvements_errors::ObservabilityContext,
    pattern_engine::{ExecutionEvent, PatternEngine},
};
use std::sync::Arc;

/// Cache key for tool results
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
struct ToolResultKey(String);

impl CacheKey for ToolResultKey {
    fn to_cache_key(&self) -> String {
        self.0.clone()
    }
}

/// Tool effectiveness metrics
#[derive(Clone, Debug)]
pub struct ToolMetrics {
    pub name: String,
    pub total_calls: usize,
    pub successful_calls: usize,
    pub total_duration_ms: u64,
    pub avg_quality: f32,
}

impl ToolMetrics {
    pub fn success_rate(&self) -> f32 {
        if self.total_calls == 0 {
            0.0
        } else {
            self.successful_calls as f32 / self.total_calls as f32
        }
    }

    pub fn avg_duration_ms(&self) -> u64 {
        if self.total_calls == 0 {
            0
        } else {
            self.total_duration_ms / self.total_calls as u64
        }
    }
}

/// ToolRegistry improvement extension (migrated to UnifiedCache)
pub struct ToolRegistryImprovement {
    pattern_engine: Arc<PatternEngine>,
    tool_metrics: Arc<parking_lot::RwLock<hashbrown::HashMap<String, ToolMetrics>>>,
    result_cache: Arc<parking_lot::RwLock<UnifiedCache<ToolResultKey, String>>>,
    obs_context: Arc<ObservabilityContext>,
}

impl ToolRegistryImprovement {
    /// Create new registry extension (now using UnifiedCache)
    pub fn new(obs_context: Arc<ObservabilityContext>) -> Self {
        Self {
            pattern_engine: Arc::new(PatternEngine::new(1000, 20)),
            tool_metrics: Arc::new(parking_lot::RwLock::new(hashbrown::HashMap::new())),
            result_cache: Arc::new(parking_lot::RwLock::new(UnifiedCache::new(
                10000,
                DEFAULT_CACHE_TTL,
                EvictionPolicy::Lru,
            ))),
            obs_context,
        }
    }

    /// Record tool execution
    pub fn record_execution(
        &self,
        tool_name: &str,
        arguments: &str,
        success: bool,
        quality_score: f32,
        duration_ms: u64,
    ) {
        // Update metrics
        {
            let mut metrics = self.tool_metrics.write();
            let entry = if let Some(m) = metrics.get_mut(tool_name) {
                m
            } else {
                metrics
                    .entry(tool_name.to_string())
                    .or_insert_with(|| ToolMetrics {
                        name: tool_name.to_string(),
                        total_calls: 0,
                        successful_calls: 0,
                        total_duration_ms: 0,
                        avg_quality: 0.0,
                    })
            };

            entry.total_calls += 1;
            if success {
                entry.successful_calls += 1;
            }
            entry.total_duration_ms += duration_ms;
            entry.avg_quality = (entry.avg_quality * (entry.total_calls as f32 - 1.0)
                + quality_score)
                / entry.total_calls as f32;
        }

        // Record pattern event
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();

        self.pattern_engine.record(ExecutionEvent {
            tool_name: tool_name.to_string(),
            arguments: arguments.to_string(),
            success,
            quality_score,
            duration_ms,
            timestamp: now,
        });

        // Log metric - avoid format! if possible, but for key names it's needed
        let metric_key = format!("{}_success_rate", tool_name);
        self.obs_context.metric("tool_effectiveness", &metric_key, {
            let metrics = self.tool_metrics.read();
            metrics
                .get(tool_name)
                .map(|m| m.success_rate())
                .unwrap_or(0.0)
        });
    }

    /// Get tool metrics
    pub fn get_tool_metrics(&self, tool_name: &str) -> Option<ToolMetrics> {
        self.tool_metrics.read().get(tool_name).cloned()
    }

    /// Get all tool metrics
    pub fn get_all_metrics(&self) -> Vec<ToolMetrics> {
        self.tool_metrics.read().values().cloned().collect()
    }

    /// Get execution summary
    pub fn get_summary(&self) -> crate::tools::pattern_engine::ExecutionSummary {
        self.pattern_engine.summary()
    }

    /// Predict next tool based on patterns
    pub fn predict_next_tool(&self) -> Option<String> {
        self.pattern_engine.predict_next_tool()
    }

    /// Cache result for tool execution (migrated to UnifiedCache)
    pub fn cache_result(&self, tool: &str, args: &str, result: &str) {
        let key = ToolResultKey(format!("{}::{}", tool, args));
        let size = result.len() as u64;
        self.result_cache
            .write()
            .insert(key, result.to_string(), size);
    }

    /// Try to get cached result (migrated to UnifiedCache)
    pub fn get_cached_result(&self, tool: &str, args: &str) -> Option<String> {
        let key = ToolResultKey(format!("{}::{}", tool, args));
        self.result_cache.write().get_owned(&key)
    }

    /// Clear cache (migrated to UnifiedCache)
    pub fn clear_cache(&self) {
        self.result_cache.write().clear();
    }

    /// Get cache stats (migrated to UnifiedCache)
    pub fn cache_stats(&self) -> crate::cache::CacheStats {
        self.result_cache.read().stats().clone()
    }

    /// Rank tools by effectiveness
    pub fn rank_tools(&self) -> Vec<(String, f32)> {
        let metrics = self.tool_metrics.read();
        let mut tools: Vec<_> = metrics
            .values()
            .map(|m| {
                let score = (m.success_rate() * 0.6)
                    + ((1.0 - (m.avg_duration_ms() as f32 / 5000.0).min(1.0)) * 0.4);
                (&m.name, score)
            })
            .collect();

        tools.sort_unstable_by(|a, b| b.1.total_cmp(&a.1));
        tools.into_iter().map(|(n, s)| (n.clone(), s)).collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::config::constants::tools;

    #[test]
    fn test_record_execution() {
        let obs = Arc::new(ObservabilityContext::noop());
        let ext = ToolRegistryImprovement::new(obs);

        ext.record_execution(tools::UNIFIED_SEARCH, "pattern", true, 0.8, 100);

        let metrics = ext.get_tool_metrics(tools::UNIFIED_SEARCH);
        assert!(metrics.is_some());
        assert_eq!(metrics.unwrap().success_rate(), 1.0);
    }

    #[test]
    fn test_cache_result() {
        let obs = Arc::new(ObservabilityContext::noop());
        let ext = ToolRegistryImprovement::new(obs);

        ext.cache_result(tools::UNIFIED_SEARCH, "pattern", "result");
        assert_eq!(
            ext.get_cached_result(tools::UNIFIED_SEARCH, "pattern"),
            Some("result".to_owned())
        );
    }

    #[test]
    fn test_rank_tools() {
        let obs = Arc::new(ObservabilityContext::noop());
        let ext = ToolRegistryImprovement::new(obs);

        ext.record_execution("tool1", "arg", true, 0.9, 100);
        ext.record_execution("tool2", "arg", false, 0.3, 50);

        let ranked = ext.rank_tools();
        assert_eq!(ranked[0].0, "tool1"); // Higher success rate
    }
}
