"""SAGE Engine - Unified API for SAGE NCS Assistant.

Main entry point that integrates RAG pipeline, tools, and query routing
into a unified interface for applications.
"""

import logging
import uuid
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

from sage.core.reasoning import (
    ReasoningChain,
    ReasoningStep,
    ReasoningVerifier,
    VerificationResult,
    VerificationStatus,
)
from sage.data_collection.interaction_logger import InteractionLogger
from sage.engine.config import EngineMode, SAGEConfig
from sage.engine.monitor import Alert, ProductionMonitor
from sage.engine.router import ComplexityLevel, QueryRouter, QueryType, RoutingDecision
from sage.engine.tools import ToolExecutionContext, ToolResult, ToolRunner
from sage.rag.pipeline import RAGResponse, SAGERAGPipeline

logger = logging.getLogger(__name__)


@dataclass
class SAGEResponse:
    """Complete response from SAGEEngine.

    Extends RAGResponse with tool results and engine-specific metadata.
    """

    # Core response
    answer: str
    query: str

    # Query routing info
    query_type: QueryType = QueryType.KNOWLEDGE
    complexity: ComplexityLevel = ComplexityLevel.SIMPLE
    routing: RoutingDecision | None = None

    # RAG response (if applicable)
    rag_response: RAGResponse | None = None

    # Tool results
    tool_results: list[ToolResult] = field(default_factory=list)

    # Quality indicators
    confidence: float = 1.0
    grounded: bool = True

    # Safety - delegated from RAG
    abstention: Any = None
    escalation: Any = None
    classification: Any = None
    escalation_request_id: str | None = None

    # Metadata
    request_id: str = ""
    latency_ms: float = 0.0
    model: str = ""
    error: str | None = None

    # Alerts triggered
    alerts: list[Alert] = field(default_factory=list)

    # Reasoning verification results (for analysis queries)
    verification_results: list[VerificationResult] = field(default_factory=list)

    @property
    def success(self) -> bool:
        """Check if response was successful."""
        return self.error is None

    @property
    def has_tool_results(self) -> bool:
        """Check if response includes tool results."""
        return len(self.tool_results) > 0

    @property
    def should_abstain(self) -> bool:
        """Check if engine abstained from answering."""
        if self.abstention:
            return self.abstention.should_abstain
        return False

    @property
    def requires_escalation(self) -> bool:
        """Check if response requires escalation."""
        if self.escalation:
            return self.escalation.should_escalate
        return False

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for API responses."""
        return {
            "answer": self.answer,
            "query": self.query,
            "query_type": self.query_type.value,
            "complexity": self.complexity.value,
            "confidence": self.confidence,
            "grounded": self.grounded,
            "tool_results": [
                {
                    "tool": r.tool_name,
                    "status": r.status.value,
                    "result": str(r.result)[:500] if r.result else None,
                    "error": r.error,
                }
                for r in self.tool_results
            ],
            "verification_results": [
                {
                    "checkpoint": v.checkpoint,
                    "status": v.status.value,
                    "message": v.message,
                    "errors": v.errors,
                    "warnings": v.warnings,
                }
                for v in self.verification_results
            ],
            "request_id": self.request_id,
            "latency_ms": self.latency_ms,
            "model": self.model,
            "error": self.error,
            "should_abstain": self.should_abstain,
            "requires_escalation": self.requires_escalation,
            "escalation_request_id": self.escalation_request_id,
        }


class SAGEEngine:
    """Unified API for SAGE NCS Assistant.

    Integrates query routing, RAG pipeline, and tools into a single
    interface for building applications.

    Example:
        # Create engine
        engine = SAGEEngine.from_config("config.yaml")
        await engine.initialize()

        # Simple query
        response = await engine.query("What is the subcritical limit for U-235?")
        print(response.answer)

        # Query with tools
        response = await engine.query(
            "Estimate k-eff for 10 kg U-235 metal sphere",
            context={"allow_tools": True}
        )
        print(response.answer)
        for tool_result in response.tool_results:
            print(f"  {tool_result.tool_name}: {tool_result.result}")

        # Cleanup
        await engine.close()
    """

    def __init__(self, config: SAGEConfig):
        """Initialize SAGE Engine.

        Args:
            config: Engine configuration.
        """
        self.config = config

        # Core components
        self.router = QueryRouter(config.router_config)
        self.tool_runner = ToolRunner(config.tool_config)
        self.monitor = ProductionMonitor(config.monitor_config)

        # RAG pipeline (initialized lazily)
        self._rag_pipeline: SAGERAGPipeline | None = None
        self._initialized = False

        # Data collection (for training data)
        self._interaction_logger: InteractionLogger | None = None
        if config.data_collection_config.enable_interaction_logging:
            self._interaction_logger = InteractionLogger(
                storage_path=config.data_collection_config.interaction_log_path,
                enabled=True,
                batch_size=config.data_collection_config.batch_size,
            )

    @classmethod
    def from_config(cls, config_path: str | Path) -> "SAGEEngine":
        """Create engine from configuration file.

        Args:
            config_path: Path to YAML configuration file.

        Returns:
            SAGEEngine instance.
        """
        config = SAGEConfig.from_yaml(config_path)
        return cls(config)

    @classmethod
    def from_dict(cls, config_dict: dict[str, Any]) -> "SAGEEngine":
        """Create engine from configuration dictionary.

        Args:
            config_dict: Configuration dictionary.

        Returns:
            SAGEEngine instance.
        """
        config = SAGEConfig.from_dict(config_dict)
        return cls(config)

    async def initialize(self) -> None:
        """Initialize engine components."""
        if self._initialized:
            return

        logger.info("Initializing SAGE Engine...")

        # Initialize RAG pipeline
        self._rag_pipeline = SAGERAGPipeline(self.config.rag_config)
        await self._rag_pipeline.initialize()

        # Initialize interaction logger if enabled
        if self._interaction_logger:
            await self._interaction_logger.initialize()
            logger.info("Interaction logging enabled for training data collection")

        self._initialized = True
        logger.info("SAGE Engine ready")

    async def close(self) -> None:
        """Clean up resources."""
        if self._rag_pipeline:
            await self._rag_pipeline.close()
        if self._interaction_logger:
            await self._interaction_logger.close()
        self._initialized = False
        logger.info("SAGE Engine closed")

    async def __aenter__(self) -> "SAGEEngine":
        """Async context manager entry."""
        await self.initialize()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
        """Async context manager exit."""
        await self.close()

    async def query(
        self,
        query: str,
        context: dict[str, Any] | None = None,
        user_id: str | None = None,
    ) -> SAGEResponse:
        """Process a query through the engine.

        Routes the query to appropriate handlers based on classification
        and executes tools as needed.

        Args:
            query: User's query string.
            context: Optional context dictionary with settings:
                - allow_tools: bool - Enable tool execution
                - force_knowledge_only: bool - Only use RAG
                - conversation_history: list - Prior conversation
                - affects_safety_basis: bool - Flag for escalation
            user_id: User identifier for tracking.

        Returns:
            SAGEResponse with answer, tool results, and metadata.
        """
        import time

        if not self._initialized:
            await self.initialize()

        context = context or {}
        user_id = user_id or self.config.default_user_id
        request_id = str(uuid.uuid4())[:8]
        start_time = time.time()

        # Start monitoring
        self.monitor.start_query(request_id)

        try:
            # Route query
            routing = self.router.route(query, context)
            self.monitor.log_query(query, routing, user_id)

            # Execute appropriate handler based on mode and query type
            if self.config.mode == EngineMode.KNOWLEDGE_ONLY:
                response = await self._handle_knowledge_query(
                    query, context, routing, request_id
                )
            elif routing.query_type == QueryType.KNOWLEDGE:
                response = await self._handle_knowledge_query(
                    query, context, routing, request_id
                )
            elif routing.query_type == QueryType.CALCULATION:
                response = await self._handle_calculation_query(
                    query, context, routing, request_id
                )
            elif routing.query_type == QueryType.ANALYSIS:
                response = await self._handle_analysis_query(
                    query, context, routing, request_id
                )
            elif routing.query_type == QueryType.DOCUMENT:
                response = await self._handle_document_query(
                    query, context, routing, request_id
                )
            elif routing.query_type == QueryType.TRAINING:
                response = await self._handle_training_query(
                    query, context, routing, request_id
                )
            else:
                response = await self._handle_knowledge_query(
                    query, context, routing, request_id
                )

            # Calculate latency
            latency_ms = (time.time() - start_time) * 1000
            response.latency_ms = latency_ms
            response.request_id = request_id

            # Log response and check alerts
            self.monitor.log_response(response, request_id, latency_ms)
            response.alerts = self.monitor.check_alerts(response)

            # Log interaction for training data collection
            if self._interaction_logger:
                try:
                    await self._interaction_logger.log_from_sage_response(
                        query=query,
                        response=response,
                        session_id=context.get("session_id"),
                        user_id=user_id,
                    )
                except Exception as log_error:
                    # Don't fail the request if logging fails
                    logger.warning(f"Failed to log interaction: {log_error}")

            return response

        except Exception as e:
            logger.error(f"Engine error: {e}")
            latency_ms = (time.time() - start_time) * 1000
            return SAGEResponse(
                answer="I encountered an error processing your query. Please try again.",
                query=query,
                query_type=QueryType.KNOWLEDGE,
                request_id=request_id,
                latency_ms=latency_ms,
                error=str(e),
            )

    async def _handle_knowledge_query(
        self,
        query: str,
        context: dict[str, Any],
        routing: RoutingDecision,
        request_id: str,
    ) -> SAGEResponse:
        """Handle knowledge/factual queries using RAG.

        Args:
            query: User's query.
            context: Request context.
            routing: Routing decision.
            request_id: Request identifier.

        Returns:
            SAGEResponse with RAG answer.
        """
        # Build context metadata for safety checks
        context_metadata = {
            "affects_safety_basis": context.get("affects_safety_basis", False),
            "query_type": routing.query_type.value,
            "complexity": routing.complexity.value,
        }

        # Execute RAG query with safety checks
        rag_response = await self._rag_pipeline.query_with_safety(
            question=query,
            user_id=context.get("user_id", "anonymous"),
            context_metadata=context_metadata,
            conversation_history=context.get("conversation_history"),
        )

        return self._build_response(query, routing, rag_response)

    async def _handle_calculation_query(
        self,
        query: str,
        context: dict[str, Any],
        routing: RoutingDecision,
        request_id: str,
    ) -> SAGEResponse:
        """Handle calculation queries with tool support.

        Args:
            query: User's query.
            context: Request context.
            routing: Routing decision.
            request_id: Request identifier.

        Returns:
            SAGEResponse with tools and RAG answer.
        """
        tool_results = []

        # Run required tools if allowed
        if context.get("allow_tools", True) and routing.required_tools:
            tool_context = ToolExecutionContext(
                user_id=context.get("user_id", "anonymous"),
                request_id=request_id,
            )

            # Build tool parameters from routing
            for tool_name in routing.required_tools:
                params = self._build_tool_params(tool_name, routing.tool_params, query)
                result = await self.tool_runner.run_tool(tool_name, params, tool_context)
                tool_results.append(result)

                # Log tool execution
                self.monitor.log_tool_execution(
                    tool_name,
                    result.success,
                    result.execution_time_ms,
                    result.error,
                )

        # Get RAG context if needed
        rag_response = None
        if routing.requires_rag:
            context_metadata = {
                "affects_safety_basis": context.get("affects_safety_basis", False),
                "query_type": routing.query_type.value,
                "tool_results": [r.tool_name for r in tool_results if r.success],
            }

            rag_response = await self._rag_pipeline.query_with_safety(
                question=query,
                user_id=context.get("user_id", "anonymous"),
                context_metadata=context_metadata,
            )

        # Synthesize response
        return await self._synthesize_response(
            query, routing, rag_response, tool_results
        )

    async def _handle_analysis_query(
        self,
        query: str,
        context: dict[str, Any],
        routing: RoutingDecision,
        request_id: str,
    ) -> SAGEResponse:
        """Handle complex analysis queries with multi-step reasoning.

        Uses ReasoningVerifier to validate reasoning chains for safety-critical
        analysis responses.

        Args:
            query: User's query.
            context: Request context.
            routing: Routing decision.
            request_id: Request identifier.

        Returns:
            SAGEResponse with analysis and verification results.
        """
        # Get initial RAG context
        context_metadata = {
            "affects_safety_basis": context.get("affects_safety_basis", True),
            "query_type": routing.query_type.value,
            "requires_verification": True,
        }

        rag_response = await self._rag_pipeline.query_with_safety(
            question=query,
            user_id=context.get("user_id", "anonymous"),
            context_metadata=context_metadata,
            task_type="analysis",
        )

        # Run any required tools
        tool_results = []
        if context.get("allow_tools", True) and routing.required_tools:
            tool_context = ToolExecutionContext(
                user_id=context.get("user_id", "anonymous"),
                request_id=request_id,
            )

            for tool_name in routing.required_tools:
                params = self._build_tool_params(tool_name, routing.tool_params, query)
                result = await self.tool_runner.run_tool(tool_name, params, tool_context)
                tool_results.append(result)

        # Synthesize response first
        response = await self._synthesize_response(
            query, routing, rag_response, tool_results
        )

        # Build reasoning chain for verification
        verification_results = await self._verify_analysis_reasoning(
            query, response, rag_response, tool_results, context
        )
        response.verification_results = verification_results

        # Log verification status
        passed = all(
            v.status in (VerificationStatus.PASSED, VerificationStatus.WARNING)
            for v in verification_results
        )
        if not passed:
            logger.warning(
                f"Analysis verification failed for request {request_id}: "
                f"{[v.message for v in verification_results if v.status == VerificationStatus.FAILED]}"
            )

        return response

    async def _verify_analysis_reasoning(
        self,
        query: str,
        response: "SAGEResponse",
        rag_response: RAGResponse | None,
        tool_results: list[ToolResult],
        context: dict[str, Any],
    ) -> list[VerificationResult]:
        """Verify reasoning chain for analysis queries.

        Builds a ReasoningChain from the response and runs verification
        checkpoints to ensure logical consistency and citation support.

        Args:
            query: Original query.
            response: Synthesized response.
            rag_response: RAG pipeline response.
            tool_results: Tool execution results.
            context: Request context.

        Returns:
            List of verification results.
        """
        # Build reasoning steps from the response components
        steps = []
        step_number = 1

        # Step 1: Query analysis
        steps.append(
            ReasoningStep(
                step_number=step_number,
                action="Analyze query",
                result=f"Query classified as {response.query_type.value} "
                f"with {response.complexity.value} complexity",
                confidence=response.confidence,
            )
        )
        step_number += 1

        # Step 2: Tool execution (if any)
        for tool_result in tool_results:
            if tool_result.success:
                steps.append(
                    ReasoningStep(
                        step_number=step_number,
                        action=f"Execute {tool_result.tool_name}",
                        result=str(tool_result.result)[:200] if tool_result.result else "Completed",
                        confidence=0.9 if tool_result.success else 0.5,
                    )
                )
                step_number += 1

        # Step 3: RAG retrieval
        if rag_response:
            # Extract citations from RAG response context if available
            citations = []
            if hasattr(rag_response, "context") and rag_response.context:
                for ctx in rag_response.context[:3]:
                    if hasattr(ctx, "doc_id"):
                        citations.append(ctx.doc_id)

            steps.append(
                ReasoningStep(
                    step_number=step_number,
                    action="Retrieve relevant context",
                    result=f"Retrieved {len(citations)} relevant sources",
                    citations=citations,
                    confidence=rag_response.confidence,
                )
            )
            step_number += 1

        # Step 4: Conclusion
        steps.append(
            ReasoningStep(
                step_number=step_number,
                action="Generate response",
                result=response.answer[:200] + ("..." if len(response.answer) > 200 else ""),
                confidence=response.confidence,
            )
        )

        # Determine classification based on confidence
        if response.confidence >= 0.8:
            classification = "GREEN"
        elif response.confidence >= 0.5:
            classification = "YELLOW"
        else:
            classification = "RED"

        # Build the reasoning chain
        chain = ReasoningChain(
            steps=steps,
            conclusion=response.answer[:500],
            confidence=response.confidence,
            classification=classification,
            citations=[c for step in steps for c in step.citations],
        )

        # Get available sources from context if provided
        available_sources = context.get("available_sources")

        # Run verification
        verifier = ReasoningVerifier(strict=context.get("strict_verification", False))
        return verifier.verify_chain(chain, available_sources)

    async def _handle_document_query(
        self,
        query: str,
        context: dict[str, Any],
        routing: RoutingDecision,
        request_id: str,
    ) -> SAGEResponse:
        """Handle document generation queries.

        Args:
            query: User's query.
            context: Request context.
            routing: Routing decision.
            request_id: Request identifier.

        Returns:
            SAGEResponse with document content.
        """
        # For document queries, use specialized prompting
        context_metadata = {
            "query_type": routing.query_type.value,
            "document_type": "technical",
        }

        rag_response = await self._rag_pipeline.query_with_safety(
            question=query,
            user_id=context.get("user_id", "anonymous"),
            context_metadata=context_metadata,
            task_type="document_drafting",
        )

        return self._build_response(query, routing, rag_response)

    async def _handle_training_query(
        self,
        query: str,
        context: dict[str, Any],
        routing: RoutingDecision,
        request_id: str,
    ) -> SAGEResponse:
        """Handle training/educational queries.

        Args:
            query: User's query.
            context: Request context.
            routing: Routing decision.
            request_id: Request identifier.

        Returns:
            SAGEResponse with educational content.
        """
        context_metadata = {
            "query_type": routing.query_type.value,
            "educational_mode": True,
        }

        rag_response = await self._rag_pipeline.query_with_safety(
            question=query,
            user_id=context.get("user_id", "anonymous"),
            context_metadata=context_metadata,
            task_type="educational",
        )

        return self._build_response(query, routing, rag_response)

    def _build_response(
        self,
        query: str,
        routing: RoutingDecision,
        rag_response: RAGResponse,
        tool_results: list[ToolResult] | None = None,
    ) -> SAGEResponse:
        """Build SAGEResponse from RAG response.

        Args:
            query: Original query.
            routing: Routing decision.
            rag_response: RAG pipeline response.
            tool_results: Optional tool results.

        Returns:
            SAGEResponse.
        """
        return SAGEResponse(
            answer=rag_response.answer,
            query=query,
            query_type=routing.query_type,
            complexity=routing.complexity,
            routing=routing,
            rag_response=rag_response,
            tool_results=tool_results or [],
            confidence=rag_response.confidence,
            grounded=rag_response.grounded,
            abstention=rag_response.abstention,
            escalation=rag_response.escalation,
            classification=rag_response.classification,
            escalation_request_id=rag_response.escalation_request_id,
            model=rag_response.model,
        )

    async def _synthesize_response(
        self,
        query: str,
        routing: RoutingDecision,
        rag_response: RAGResponse | None,
        tool_results: list[ToolResult],
    ) -> SAGEResponse:
        """Synthesize response combining RAG and tool results.

        Args:
            query: Original query.
            routing: Routing decision.
            rag_response: RAG pipeline response (may be None).
            tool_results: Tool execution results.

        Returns:
            SAGEResponse with synthesized answer.
        """
        # Build answer combining RAG and tools
        answer_parts = []

        # Include RAG answer if available
        if rag_response:
            answer_parts.append(rag_response.answer)

        # Add tool results summary
        if tool_results:
            tool_summary = self.tool_runner.format_tool_results(tool_results)
            if tool_summary:
                answer_parts.append("")
                answer_parts.append(tool_summary)

        answer = "\n".join(answer_parts)

        # Build response
        response = SAGEResponse(
            answer=answer,
            query=query,
            query_type=routing.query_type,
            complexity=routing.complexity,
            routing=routing,
            rag_response=rag_response,
            tool_results=tool_results,
            confidence=rag_response.confidence if rag_response else 0.8,
            grounded=rag_response.grounded if rag_response else True,
        )

        # Copy safety results from RAG if available
        if rag_response:
            response.abstention = rag_response.abstention
            response.escalation = rag_response.escalation
            response.classification = rag_response.classification
            response.escalation_request_id = rag_response.escalation_request_id
            response.model = rag_response.model

        return response

    def _build_tool_params(
        self,
        tool_name: str,
        extracted_params: dict[str, Any],
        query: str,
    ) -> dict[str, Any]:
        """Build parameters for a specific tool.

        Args:
            tool_name: Name of the tool.
            extracted_params: Parameters extracted by router.
            query: Original query for additional context.

        Returns:
            Parameters dictionary for the tool.
        """
        params: dict[str, Any] = {}

        if tool_name == "keff_estimator":
            # Extract material
            materials = extracted_params.get("materials", [])
            if materials:
                params["material"] = self._normalize_material(materials[0])

            # Extract numeric values
            numeric_values = extracted_params.get("numeric_values", [])
            for val in numeric_values:
                unit = val.get("unit", "").lower()
                value = val.get("value", 0)
                if unit in ("kg", "g", "lb"):
                    if unit == "g":
                        params["mass_kg"] = value / 1000
                    elif unit == "lb":
                        params["mass_kg"] = value * 0.453592
                    else:
                        params["mass_kg"] = value

            # Extract geometry
            geometries = extracted_params.get("geometries", [])
            if geometries:
                params["geometry"] = geometries[0]
            else:
                params["geometry"] = "sphere"  # Default

            # Extract enrichment
            if "enrichment" in extracted_params:
                params["enrichment"] = extracted_params["enrichment"] / 100

            # Default form
            params["form"] = "metal"

        elif tool_name == "unit_converter":
            numeric_values = extracted_params.get("numeric_values", [])
            if numeric_values:
                params["value"] = numeric_values[0].get("value", 0)
                params["from_unit"] = numeric_values[0].get("unit", "")
                # Determine target unit from query context
                params["to_unit"] = self._infer_target_unit(query, params["from_unit"])

        elif tool_name == "standards_lookup":
            # Extract standard reference from query
            params["standard_id"] = "ANSI/ANS-8.1-2014"  # Default

        elif tool_name == "scale_interface":
            # Similar to keff_estimator
            materials = extracted_params.get("materials", [])
            if materials:
                params["material"] = self._normalize_material(materials[0])
            params["geometry"] = extracted_params.get("geometries", ["sphere"])[0]
            if "enrichment" in extracted_params:
                params["enrichment"] = extracted_params["enrichment"] / 100

        return params

    def _normalize_material(self, material: str) -> str:
        """Normalize material name to standard format.

        Args:
            material: Raw material string.

        Returns:
            Normalized material name.
        """
        material_map = {
            "u235": "U-235",
            "u-235": "U-235",
            "uranium": "U-235",
            "u238": "U-238",
            "u-238": "U-238",
            "pu239": "Pu-239",
            "pu-239": "Pu-239",
            "plutonium": "Pu-239",
            "pu240": "Pu-240",
            "pu-240": "Pu-240",
            "u233": "U-233",
            "u-233": "U-233",
        }
        return material_map.get(material.lower(), material.upper())

    def _infer_target_unit(self, query: str, from_unit: str) -> str:
        """Infer target unit from query context.

        Args:
            query: Original query.
            from_unit: Source unit.

        Returns:
            Inferred target unit.
        """
        query_lower = query.lower()

        # Check for explicit target
        unit_patterns = {
            "kg": ["kg", "kilogram"],
            "g": ["gram", " g "],
            "L": ["liter", " l "],
            "mL": ["ml", "milliliter"],
            "cm": ["cm", "centimeter"],
            "m": ["meter", " m "],
        }

        for unit, patterns in unit_patterns.items():
            if unit.lower() != from_unit.lower():
                for pattern in patterns:
                    if pattern.lower() in query_lower:
                        return unit

        # Default conversions
        default_targets = {
            "kg": "g",
            "g": "kg",
            "L": "mL",
            "mL": "L",
            "m": "cm",
            "cm": "m",
        }
        return default_targets.get(from_unit, from_unit)

    # Convenience methods

    async def index_document(
        self,
        file_path: Path,
        doc_id: str,
        source: str = "unknown",
        title: str | None = None,
    ) -> dict[str, Any]:
        """Index a document into the knowledge base.

        Args:
            file_path: Path to document file.
            doc_id: Document identifier.
            source: Document source.
            title: Optional title.

        Returns:
            Indexing statistics.
        """
        if not self._initialized:
            await self.initialize()

        return await self._rag_pipeline.index_document(
            file_path=file_path,
            doc_id=doc_id,
            source=source,
            title=title,
        )

    def get_metrics(self) -> dict[str, Any]:
        """Get current engine metrics.

        Returns:
            Dictionary of metrics.
        """
        return self.monitor.export_metrics()

    def get_available_tools(self) -> dict[str, str]:
        """Get list of available tools.

        Returns:
            Dictionary mapping tool names to descriptions.
        """
        return self.tool_runner.get_available_tools()

    def get_interaction_logger(self) -> InteractionLogger | None:
        """Get the interaction logger for training data export.

        Returns:
            InteractionLogger instance if enabled, None otherwise.
        """
        return self._interaction_logger

    def get_data_collection_stats(self) -> dict[str, Any]:
        """Get statistics about collected training data.

        Returns:
            Dictionary of statistics, or empty dict if logging disabled.
        """
        if self._interaction_logger:
            return self._interaction_logger.get_statistics()
        return {"enabled": False}
