"""
Analytics Agent

Autonomous data analysis agent with capabilities:
- Statistical analysis
- Trend detection
- Anomaly detection
- Report generation
- Data profiling
"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Any

from ..config import Config, get_config

logger = logging.getLogger(__name__)


class AnalysisType(str, Enum):
    """Types of analysis."""
    STATISTICAL = "statistical"
    TREND = "trend"
    ANOMALY = "anomaly"
    PROFILE = "profile"
    CORRELATION = "correlation"
    COMPARISON = "comparison"


class TrendDirection(str, Enum):
    """Trend direction."""
    INCREASING = "increasing"
    DECREASING = "decreasing"
    STABLE = "stable"
    VOLATILE = "volatile"


@dataclass
class AnalysisResult:
    """Result of an analysis operation."""
    success: bool
    analysis_type: AnalysisType
    summary: str
    metrics: dict[str, Any] = field(default_factory=dict)
    insights: list[str] = field(default_factory=list)
    recommendations: list[str] = field(default_factory=list)
    visualizations: list[dict] = field(default_factory=list)
    error: str | None = None
    analyzed_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))


# Tool definitions for Analytics Agent
ANALYTICS_TOOLS = [
    {
        "name": "analyze_statistics",
        "description": "Compute statistical summary of numerical data (mean, median, std, percentiles).",
        "input_schema": {
            "type": "object",
            "properties": {
                "data": {"type": "array", "items": {"type": "number"}, "description": "Numerical data to analyze"},
                "column_name": {"type": "string", "description": "Name of the metric"},
                "percentiles": {"type": "array", "items": {"type": "number"}, "default": [25, 50, 75, 90, 95, 99]},
            },
            "required": ["data"],
        },
    },
    {
        "name": "detect_trend",
        "description": "Detect trends in time-series data.",
        "input_schema": {
            "type": "object",
            "properties": {
                "values": {"type": "array", "items": {"type": "number"}, "description": "Time-series values"},
                "timestamps": {"type": "array", "items": {"type": "string"}, "description": "Timestamps (optional)"},
                "window_size": {"type": "integer", "default": 7, "description": "Moving average window"},
            },
            "required": ["values"],
        },
    },
    {
        "name": "detect_anomalies",
        "description": "Detect anomalies in data using statistical methods.",
        "input_schema": {
            "type": "object",
            "properties": {
                "data": {"type": "array", "items": {"type": "number"}, "description": "Data to analyze"},
                "method": {"type": "string", "enum": ["zscore", "iqr", "mad"], "default": "zscore"},
                "threshold": {"type": "number", "default": 3.0, "description": "Anomaly threshold"},
            },
            "required": ["data"],
        },
    },
    {
        "name": "profile_data",
        "description": "Generate a data profile with completeness, distribution, and quality metrics.",
        "input_schema": {
            "type": "object",
            "properties": {
                "data": {"type": "array", "items": {"type": "object"}, "description": "Array of records to profile"},
                "sample_size": {"type": "integer", "default": 1000, "description": "Max records to analyze"},
            },
            "required": ["data"],
        },
    },
    {
        "name": "compare_datasets",
        "description": "Compare two datasets and identify differences.",
        "input_schema": {
            "type": "object",
            "properties": {
                "dataset_a": {"type": "array", "items": {"type": "number"}, "description": "First dataset"},
                "dataset_b": {"type": "array", "items": {"type": "number"}, "description": "Second dataset"},
                "labels": {"type": "array", "items": {"type": "string"}, "description": "Dataset labels"},
            },
            "required": ["dataset_a", "dataset_b"],
        },
    },
    {
        "name": "calculate_correlation",
        "description": "Calculate correlation between two variables.",
        "input_schema": {
            "type": "object",
            "properties": {
                "x": {"type": "array", "items": {"type": "number"}, "description": "First variable"},
                "y": {"type": "array", "items": {"type": "number"}, "description": "Second variable"},
                "method": {"type": "string", "enum": ["pearson", "spearman"], "default": "pearson"},
            },
            "required": ["x", "y"],
        },
    },
    {
        "name": "generate_report",
        "description": "Generate a comprehensive analysis report.",
        "input_schema": {
            "type": "object",
            "properties": {
                "data": {"type": "array", "items": {"type": "object"}, "description": "Data to report on"},
                "title": {"type": "string", "description": "Report title"},
                "include_visualizations": {"type": "boolean", "default": True},
            },
            "required": ["data", "title"],
        },
    },
    {
        "name": "forecast_values",
        "description": "Generate simple forecasts based on historical data.",
        "input_schema": {
            "type": "object",
            "properties": {
                "values": {"type": "array", "items": {"type": "number"}, "description": "Historical values"},
                "periods": {"type": "integer", "default": 7, "description": "Periods to forecast"},
                "method": {"type": "string", "enum": ["linear", "moving_avg", "exponential"], "default": "linear"},
            },
            "required": ["values"],
        },
    },
]


class AnalyticsAgent:
    """
    Autonomous Data Analytics Agent.

    Provides statistical analysis, trend detection, anomaly detection,
    and report generation capabilities.
    """

    def __init__(
        self,
        config: Config | None = None,
        tools: list[dict] | None = None,
    ):
        """
        Initialize Analytics Agent.

        Args:
            config: Configuration object
            tools: Custom tool definitions
        """
        self.config = config or get_config()
        self.tools = tools or ANALYTICS_TOOLS
        self._analysis_history: list[AnalysisResult] = []
        logger.info("AnalyticsAgent initialized")

    def analyze_statistics(
        self,
        data: list[float | int],
        column_name: str = "value",
        percentiles: list[float] | None = None,
    ) -> AnalysisResult:
        """
        Compute statistical summary of numerical data.

        Args:
            data: Numerical data to analyze
            column_name: Name of the metric
            percentiles: Percentiles to calculate
        """
        import statistics

        if not data:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.STATISTICAL,
                summary="No data provided",
                error="Empty dataset",
            )

        percentiles = percentiles or [25, 50, 75, 90, 95, 99]

        try:
            sorted_data = sorted(data)
            n = len(data)

            # Calculate percentiles manually
            def percentile(p: float) -> float:
                k = (n - 1) * (p / 100)
                f = int(k)
                c = f + 1 if f + 1 < n else f
                return sorted_data[f] + (sorted_data[c] - sorted_data[f]) * (k - f)

            metrics = {
                "count": n,
                "mean": statistics.mean(data),
                "median": statistics.median(data),
                "std": statistics.stdev(data) if n > 1 else 0,
                "min": min(data),
                "max": max(data),
                "range": max(data) - min(data),
                "sum": sum(data),
            }

            # Add percentiles
            for p in percentiles:
                metrics[f"p{int(p)}"] = percentile(p)

            # Generate insights
            insights = []
            if metrics["std"] > metrics["mean"] * 0.5:
                insights.append(f"High variability detected (CV = {metrics['std']/metrics['mean']:.2f})")
            if metrics["median"] != metrics["mean"]:
                skew = "right" if metrics["mean"] > metrics["median"] else "left"
                insights.append(f"Distribution is skewed {skew}")

            result = AnalysisResult(
                success=True,
                analysis_type=AnalysisType.STATISTICAL,
                summary=f"Statistical analysis of {column_name}: mean={metrics['mean']:.2f}, median={metrics['median']:.2f}",
                metrics=metrics,
                insights=insights,
            )
            self._analysis_history.append(result)
            return result

        except Exception as e:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.STATISTICAL,
                summary="Analysis failed",
                error=str(e),
            )

    def detect_trend(
        self,
        values: list[float | int],
        timestamps: list[str] | None = None,
        window_size: int = 7,
    ) -> AnalysisResult:
        """
        Detect trends in time-series data.

        Args:
            values: Time-series values
            timestamps: Optional timestamps
            window_size: Moving average window size
        """
        if len(values) < 3:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.TREND,
                summary="Insufficient data for trend analysis",
                error="Need at least 3 data points",
            )

        try:
            # Calculate moving average
            ma = []
            for i in range(len(values)):
                start = max(0, i - window_size + 1)
                ma.append(sum(values[start:i+1]) / (i - start + 1))

            # Determine trend direction
            first_half = sum(values[:len(values)//2]) / (len(values)//2)
            second_half = sum(values[len(values)//2:]) / (len(values) - len(values)//2)

            change_pct = (second_half - first_half) / first_half * 100 if first_half != 0 else 0

            if abs(change_pct) < 5:
                direction = TrendDirection.STABLE
            elif change_pct > 0:
                direction = TrendDirection.INCREASING
            else:
                direction = TrendDirection.DECREASING

            # Check volatility
            import statistics
            std = statistics.stdev(values) if len(values) > 1 else 0
            mean = statistics.mean(values)
            cv = std / mean if mean != 0 else 0

            if cv > 0.3:
                direction = TrendDirection.VOLATILE

            metrics = {
                "direction": direction.value,
                "change_percent": change_pct,
                "first_value": values[0],
                "last_value": values[-1],
                "moving_average": ma[-1],
                "volatility": cv,
            }

            insights = [
                f"Trend direction: {direction.value}",
                f"Overall change: {change_pct:+.1f}%",
            ]

            if direction == TrendDirection.VOLATILE:
                insights.append(f"High volatility detected (CV = {cv:.2f})")

            result = AnalysisResult(
                success=True,
                analysis_type=AnalysisType.TREND,
                summary=f"Trend: {direction.value} ({change_pct:+.1f}%)",
                metrics=metrics,
                insights=insights,
            )
            self._analysis_history.append(result)
            return result

        except Exception as e:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.TREND,
                summary="Trend analysis failed",
                error=str(e),
            )

    def detect_anomalies(
        self,
        data: list[float | int],
        method: str = "zscore",
        threshold: float = 3.0,
    ) -> AnalysisResult:
        """
        Detect anomalies in data.

        Args:
            data: Data to analyze
            method: Detection method (zscore, iqr, mad)
            threshold: Anomaly threshold
        """
        import statistics

        if len(data) < 3:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.ANOMALY,
                summary="Insufficient data",
                error="Need at least 3 data points",
            )

        try:
            anomalies = []
            mean = statistics.mean(data)
            std = statistics.stdev(data)

            if method == "zscore":
                for i, value in enumerate(data):
                    z = (value - mean) / std if std > 0 else 0
                    if abs(z) > threshold:
                        anomalies.append({
                            "index": i,
                            "value": value,
                            "zscore": z,
                            "severity": "high" if abs(z) > threshold * 1.5 else "medium",
                        })

            elif method == "iqr":
                sorted_data = sorted(data)
                n = len(data)
                q1 = sorted_data[n // 4]
                q3 = sorted_data[3 * n // 4]
                iqr = q3 - q1
                lower = q1 - threshold * iqr
                upper = q3 + threshold * iqr

                for i, value in enumerate(data):
                    if value < lower or value > upper:
                        anomalies.append({
                            "index": i,
                            "value": value,
                            "bounds": [lower, upper],
                            "severity": "high" if value < lower - iqr or value > upper + iqr else "medium",
                        })

            elif method == "mad":
                median = statistics.median(data)
                mad = statistics.median([abs(x - median) for x in data])
                mad_threshold = threshold * 1.4826 * mad

                for i, value in enumerate(data):
                    deviation = abs(value - median)
                    if deviation > mad_threshold:
                        anomalies.append({
                            "index": i,
                            "value": value,
                            "deviation": deviation,
                            "severity": "high" if deviation > mad_threshold * 1.5 else "medium",
                        })

            metrics = {
                "method": method,
                "threshold": threshold,
                "total_points": len(data),
                "anomaly_count": len(anomalies),
                "anomaly_rate": len(anomalies) / len(data),
                "anomalies": anomalies[:20],  # Limit to top 20
            }

            insights = []
            if anomalies:
                insights.append(f"Found {len(anomalies)} anomalies ({len(anomalies)/len(data)*100:.1f}%)")
                high_severity = sum(1 for a in anomalies if a.get("severity") == "high")
                if high_severity:
                    insights.append(f"{high_severity} high-severity anomalies detected")
            else:
                insights.append("No anomalies detected")

            result = AnalysisResult(
                success=True,
                analysis_type=AnalysisType.ANOMALY,
                summary=f"Found {len(anomalies)} anomalies using {method} method",
                metrics=metrics,
                insights=insights,
            )
            self._analysis_history.append(result)
            return result

        except Exception as e:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.ANOMALY,
                summary="Anomaly detection failed",
                error=str(e),
            )

    def profile_data(
        self,
        data: list[dict[str, Any]],
        sample_size: int = 1000,
    ) -> AnalysisResult:
        """
        Generate a data profile.

        Args:
            data: Array of records to profile
            sample_size: Max records to analyze
        """
        if not data:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.PROFILE,
                summary="No data provided",
                error="Empty dataset",
            )

        try:
            # Sample if needed
            sample = data[:sample_size]

            # Get all columns
            all_columns = set()
            for record in sample:
                all_columns.update(record.keys())

            column_profiles = {}
            for col in all_columns:
                values = [r.get(col) for r in sample]
                non_null = [v for v in values if v is not None]

                profile = {
                    "total": len(values),
                    "non_null": len(non_null),
                    "null": len(values) - len(non_null),
                    "completeness": len(non_null) / len(values) if values else 0,
                }

                # Detect type
                if non_null:
                    sample_val = non_null[0]
                    if isinstance(sample_val, bool):
                        profile["type"] = "boolean"
                    elif isinstance(sample_val, int):
                        profile["type"] = "integer"
                    elif isinstance(sample_val, float):
                        profile["type"] = "float"
                    elif isinstance(sample_val, str):
                        profile["type"] = "string"
                        profile["unique"] = len(set(non_null))
                        profile["avg_length"] = sum(len(str(v)) for v in non_null) / len(non_null)
                    else:
                        profile["type"] = "object"

                    # Numeric stats
                    if profile.get("type") in ("integer", "float"):
                        numeric = [float(v) for v in non_null if isinstance(v, (int, float))]
                        if numeric:
                            import statistics
                            profile["min"] = min(numeric)
                            profile["max"] = max(numeric)
                            profile["mean"] = statistics.mean(numeric)

                column_profiles[col] = profile

            # Quality score
            completeness_scores = [p["completeness"] for p in column_profiles.values()]
            overall_completeness = sum(completeness_scores) / len(completeness_scores) if completeness_scores else 0

            metrics = {
                "total_records": len(data),
                "sampled_records": len(sample),
                "columns": len(all_columns),
                "column_profiles": column_profiles,
                "overall_completeness": overall_completeness,
            }

            insights = []
            if overall_completeness < 0.9:
                insights.append(f"Data completeness is {overall_completeness*100:.1f}% - consider data cleaning")

            incomplete_cols = [
                col for col, p in column_profiles.items()
                if p["completeness"] < 0.8
            ]
            if incomplete_cols:
                insights.append(f"Columns with missing data: {', '.join(incomplete_cols[:5])}")

            result = AnalysisResult(
                success=True,
                analysis_type=AnalysisType.PROFILE,
                summary=f"Profiled {len(sample)} records with {len(all_columns)} columns",
                metrics=metrics,
                insights=insights,
            )
            self._analysis_history.append(result)
            return result

        except Exception as e:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.PROFILE,
                summary="Data profiling failed",
                error=str(e),
            )

    def compare_datasets(
        self,
        dataset_a: list[float | int],
        dataset_b: list[float | int],
        labels: list[str] | None = None,
    ) -> AnalysisResult:
        """
        Compare two datasets.

        Args:
            dataset_a: First dataset
            dataset_b: Second dataset
            labels: Dataset labels
        """
        import statistics

        labels = labels or ["Dataset A", "Dataset B"]

        try:
            stats_a = {
                "count": len(dataset_a),
                "mean": statistics.mean(dataset_a) if dataset_a else 0,
                "median": statistics.median(dataset_a) if dataset_a else 0,
                "std": statistics.stdev(dataset_a) if len(dataset_a) > 1 else 0,
            }

            stats_b = {
                "count": len(dataset_b),
                "mean": statistics.mean(dataset_b) if dataset_b else 0,
                "median": statistics.median(dataset_b) if dataset_b else 0,
                "std": statistics.stdev(dataset_b) if len(dataset_b) > 1 else 0,
            }

            # Calculate differences
            mean_diff = stats_a["mean"] - stats_b["mean"]
            mean_diff_pct = (mean_diff / stats_b["mean"] * 100) if stats_b["mean"] != 0 else 0

            metrics = {
                labels[0]: stats_a,
                labels[1]: stats_b,
                "mean_difference": mean_diff,
                "mean_difference_percent": mean_diff_pct,
            }

            insights = []
            if abs(mean_diff_pct) > 10:
                direction = "higher" if mean_diff > 0 else "lower"
                insights.append(f"{labels[0]} mean is {abs(mean_diff_pct):.1f}% {direction} than {labels[1]}")

            if stats_a["std"] > stats_b["std"] * 1.5:
                insights.append(f"{labels[0]} has higher variability than {labels[1]}")
            elif stats_b["std"] > stats_a["std"] * 1.5:
                insights.append(f"{labels[1]} has higher variability than {labels[0]}")

            result = AnalysisResult(
                success=True,
                analysis_type=AnalysisType.COMPARISON,
                summary=f"Comparison: {labels[0]} vs {labels[1]} - {mean_diff_pct:+.1f}% difference in means",
                metrics=metrics,
                insights=insights,
            )
            self._analysis_history.append(result)
            return result

        except Exception as e:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.COMPARISON,
                summary="Comparison failed",
                error=str(e),
            )

    def calculate_correlation(
        self,
        x: list[float | int],
        y: list[float | int],
        method: str = "pearson",
    ) -> AnalysisResult:
        """
        Calculate correlation between two variables.

        Args:
            x: First variable
            y: Second variable
            method: Correlation method (pearson or spearman)
        """
        if len(x) != len(y):
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.CORRELATION,
                summary="Arrays must have same length",
                error=f"x has {len(x)} elements, y has {len(y)} elements",
            )

        if len(x) < 3:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.CORRELATION,
                summary="Insufficient data",
                error="Need at least 3 data points",
            )

        try:
            import statistics

            if method == "pearson":
                # Calculate Pearson correlation
                mean_x = statistics.mean(x)
                mean_y = statistics.mean(y)

                numerator = sum((xi - mean_x) * (yi - mean_y) for xi, yi in zip(x, y))
                denominator_x = sum((xi - mean_x) ** 2 for xi in x) ** 0.5
                denominator_y = sum((yi - mean_y) ** 2 for yi in y) ** 0.5

                if denominator_x == 0 or denominator_y == 0:
                    correlation = 0
                else:
                    correlation = numerator / (denominator_x * denominator_y)

            elif method == "spearman":
                # Calculate Spearman rank correlation
                def rank(data):
                    sorted_indices = sorted(range(len(data)), key=lambda i: data[i])
                    ranks = [0] * len(data)
                    for rank_val, idx in enumerate(sorted_indices):
                        ranks[idx] = rank_val + 1
                    return ranks

                rank_x = rank(x)
                rank_y = rank(y)

                n = len(x)
                d_squared = sum((rx - ry) ** 2 for rx, ry in zip(rank_x, rank_y))
                correlation = 1 - (6 * d_squared) / (n * (n ** 2 - 1))

            else:
                return AnalysisResult(
                    success=False,
                    analysis_type=AnalysisType.CORRELATION,
                    summary=f"Unknown method: {method}",
                    error=f"Method must be 'pearson' or 'spearman'",
                )

            # Interpret correlation
            abs_corr = abs(correlation)
            if abs_corr >= 0.8:
                strength = "very strong"
            elif abs_corr >= 0.6:
                strength = "strong"
            elif abs_corr >= 0.4:
                strength = "moderate"
            elif abs_corr >= 0.2:
                strength = "weak"
            else:
                strength = "very weak"

            direction = "positive" if correlation > 0 else "negative"

            metrics = {
                "method": method,
                "correlation": correlation,
                "strength": strength,
                "direction": direction,
                "r_squared": correlation ** 2,
                "n": len(x),
            }

            insights = [
                f"{strength.title()} {direction} correlation (r = {correlation:.3f})",
                f"R² = {correlation**2:.3f} ({correlation**2*100:.1f}% variance explained)",
            ]

            result = AnalysisResult(
                success=True,
                analysis_type=AnalysisType.CORRELATION,
                summary=f"{method.title()} correlation: r = {correlation:.3f} ({strength} {direction})",
                metrics=metrics,
                insights=insights,
            )
            self._analysis_history.append(result)
            return result

        except Exception as e:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.CORRELATION,
                summary="Correlation calculation failed",
                error=str(e),
            )

    def forecast_values(
        self,
        values: list[float | int],
        periods: int = 7,
        method: str = "linear",
    ) -> AnalysisResult:
        """
        Generate simple forecasts.

        Args:
            values: Historical values
            periods: Periods to forecast
            method: Forecasting method
        """
        if len(values) < 3:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.TREND,
                summary="Insufficient data for forecasting",
                error="Need at least 3 historical values",
            )

        try:
            forecasts = []

            if method == "linear":
                # Simple linear regression
                n = len(values)
                x = list(range(n))
                mean_x = sum(x) / n
                mean_y = sum(values) / n

                numerator = sum((xi - mean_x) * (yi - mean_y) for xi, yi in zip(x, values))
                denominator = sum((xi - mean_x) ** 2 for xi in x)

                slope = numerator / denominator if denominator != 0 else 0
                intercept = mean_y - slope * mean_x

                for i in range(periods):
                    forecast = slope * (n + i) + intercept
                    forecasts.append(forecast)

            elif method == "moving_avg":
                window = min(7, len(values))
                last_avg = sum(values[-window:]) / window
                forecasts = [last_avg] * periods

            elif method == "exponential":
                alpha = 0.3
                smoothed = values[0]
                for val in values[1:]:
                    smoothed = alpha * val + (1 - alpha) * smoothed
                forecasts = [smoothed] * periods

            metrics = {
                "method": method,
                "historical_count": len(values),
                "forecast_periods": periods,
                "forecasts": forecasts,
                "last_value": values[-1],
                "forecast_mean": sum(forecasts) / len(forecasts),
            }

            insights = [
                f"Generated {periods} forecasts using {method} method",
                f"Forecast range: {min(forecasts):.2f} to {max(forecasts):.2f}",
            ]

            result = AnalysisResult(
                success=True,
                analysis_type=AnalysisType.TREND,
                summary=f"{periods} period forecast: mean = {metrics['forecast_mean']:.2f}",
                metrics=metrics,
                insights=insights,
            )
            self._analysis_history.append(result)
            return result

        except Exception as e:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.TREND,
                summary="Forecasting failed",
                error=str(e),
            )

    def generate_report(
        self,
        data: list[dict[str, Any]],
        title: str,
        include_visualizations: bool = True,
    ) -> AnalysisResult:
        """
        Generate a comprehensive analysis report.

        Args:
            data: Data to report on
            title: Report title
            include_visualizations: Include chart specifications
        """
        if not data:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.PROFILE,
                summary="No data provided",
                error="Empty dataset",
            )

        try:
            # Profile the data
            profile = self.profile_data(data)

            # Find numeric columns and analyze
            numeric_analyses = {}
            if profile.metrics.get("column_profiles"):
                for col, prof in profile.metrics["column_profiles"].items():
                    if prof.get("type") in ("integer", "float"):
                        values = [r.get(col) for r in data if isinstance(r.get(col), (int, float))]
                        if values:
                            stats = self.analyze_statistics(values, col)
                            numeric_analyses[col] = stats.metrics

            visualizations = []
            if include_visualizations and numeric_analyses:
                for col, stats in list(numeric_analyses.items())[:5]:
                    visualizations.append({
                        "type": "histogram",
                        "title": f"Distribution of {col}",
                        "column": col,
                    })

            insights = profile.insights.copy()
            recommendations = []

            # Add recommendations based on analysis
            if profile.metrics.get("overall_completeness", 1) < 0.9:
                recommendations.append("Consider implementing data validation at source")
            if len(data) < 100:
                recommendations.append("Small dataset - results may not be statistically significant")

            result = AnalysisResult(
                success=True,
                analysis_type=AnalysisType.PROFILE,
                summary=f"Report: {title}",
                metrics={
                    "title": title,
                    "data_profile": profile.metrics,
                    "numeric_analyses": numeric_analyses,
                    "generated_at": datetime.now(timezone.utc).isoformat(),
                },
                insights=insights,
                recommendations=recommendations,
                visualizations=visualizations,
            )
            self._analysis_history.append(result)
            return result

        except Exception as e:
            return AnalysisResult(
                success=False,
                analysis_type=AnalysisType.PROFILE,
                summary="Report generation failed",
                error=str(e),
            )

    def handle_tool_call(self, tool_name: str, tool_input: dict[str, Any]) -> dict[str, Any]:
        """Handle a tool call from the LLM."""
        if tool_name == "analyze_statistics":
            result = self.analyze_statistics(**tool_input)
        elif tool_name == "detect_trend":
            result = self.detect_trend(**tool_input)
        elif tool_name == "detect_anomalies":
            result = self.detect_anomalies(**tool_input)
        elif tool_name == "profile_data":
            result = self.profile_data(**tool_input)
        elif tool_name == "compare_datasets":
            result = self.compare_datasets(**tool_input)
        elif tool_name == "calculate_correlation":
            result = self.calculate_correlation(**tool_input)
        elif tool_name == "generate_report":
            result = self.generate_report(**tool_input)
        elif tool_name == "forecast_values":
            result = self.forecast_values(**tool_input)
        else:
            return {"error": f"Unknown tool: {tool_name}"}

        return {
            "success": result.success,
            "analysis_type": result.analysis_type.value,
            "summary": result.summary,
            "metrics": result.metrics,
            "insights": result.insights,
            "recommendations": result.recommendations,
            "error": result.error,
        }


__all__ = [
    "AnalyticsAgent",
    "AnalysisType",
    "AnalysisResult",
    "TrendDirection",
    "ANALYTICS_TOOLS",
]
