"""Statistical analysis tools."""

import statistics

from pydantic_ai.toolsets import FunctionToolset

analysis_toolset: FunctionToolset[None] = FunctionToolset()


@analysis_toolset.tool
def calculate_statistics(data: list[float]) -> str:
    """Calculate basic statistics for a dataset.

    Args:
        data: List of numeric values to analyze.
    """
    if not data:
        return "Error: Empty dataset provided."

    if len(data) == 1:
        return f"Single value: {data[0]}"

    result = f"""Statistical Summary:
- Count: {len(data)}
- Sum: {sum(data):.2f}
- Mean: {statistics.mean(data):.2f}
- Median: {statistics.median(data):.2f}
- Std Dev: {statistics.stdev(data):.2f}
- Min: {min(data):.2f}
- Max: {max(data):.2f}
- Range: {max(data) - min(data):.2f}"""

    return result


@analysis_toolset.tool
def calculate_percentiles(
    data: list[float],
    percentiles: list[int] | None = None,
) -> str:
    """Calculate percentiles for a dataset.

    Args:
        data: List of numeric values.
        percentiles: List of percentiles to calculate (default: 25, 50, 75, 90, 95).
    """
    if not data:
        return "Error: Empty dataset provided."

    if percentiles is None:
        percentiles = [25, 50, 75, 90, 95]

    sorted_data = sorted(data)
    results = []

    for p in percentiles:
        idx = (len(sorted_data) - 1) * p / 100
        lower = int(idx)
        upper = lower + 1
        weight = idx - lower

        if upper >= len(sorted_data):
            value = sorted_data[-1]
        else:
            value = sorted_data[lower] * (1 - weight) + sorted_data[upper] * weight

        results.append(f"- P{p}: {value:.2f}")

    return "Percentiles:\n" + "\n".join(results)


@analysis_toolset.tool
def detect_outliers(
    data: list[float],
    method: str = "iqr",
) -> str:
    """Detect outliers in a dataset.

    Args:
        data: List of numeric values.
        method: Detection method - 'iqr' (interquartile range) or 'zscore'.
    """
    if len(data) < 4:
        return "Error: Need at least 4 data points for outlier detection."

    outliers = []
    sorted_data = sorted(data)

    if method == "iqr":
        q1_idx = len(sorted_data) // 4
        q3_idx = 3 * len(sorted_data) // 4
        q1 = sorted_data[q1_idx]
        q3 = sorted_data[q3_idx]
        iqr = q3 - q1
        lower_bound = q1 - 1.5 * iqr
        upper_bound = q3 + 1.5 * iqr

        outliers = [x for x in data if x < lower_bound or x > upper_bound]
        bounds_info = f"Bounds: [{lower_bound:.2f}, {upper_bound:.2f}]"

    elif method == "zscore":
        mean = statistics.mean(data)
        std = statistics.stdev(data)
        outliers = [x for x in data if abs((x - mean) / std) > 3]
        bounds_info = "Using Z-score threshold: 3"

    else:
        return f"Error: Unknown method '{method}'. Use 'iqr' or 'zscore'."

    if not outliers:
        return f"No outliers detected using {method} method.\n{bounds_info}"

    return f"""Outliers detected ({method} method):
{bounds_info}
Found {len(outliers)} outlier(s): {outliers}"""


@analysis_toolset.tool
def analyze_trend(
    values: list[float],
    labels: list[str] | None = None,
) -> str:
    """Analyze trends in sequential data.

    Args:
        values: Sequential numeric values (e.g., time series).
        labels: Optional labels for each value (e.g., dates).
    """
    if len(values) < 2:
        return "Error: Need at least 2 values for trend analysis."

    # Calculate simple linear regression
    n = len(values)
    x = list(range(n))
    x_mean = sum(x) / n
    y_mean = sum(values) / n

    numerator = sum((x[i] - x_mean) * (values[i] - y_mean) for i in range(n))
    denominator = sum((x[i] - x_mean) ** 2 for i in range(n))

    slope = 0 if denominator == 0 else numerator / denominator

    # Determine trend direction
    if slope > 0.01:
        direction = "increasing"
    elif slope < -0.01:
        direction = "decreasing"
    else:
        direction = "stable"

    # Calculate percent change
    pct_change = (values[-1] - values[0]) / abs(values[0]) * 100 if values[0] != 0 else 0

    result = f"""Trend Analysis:
- Direction: {direction}
- Slope: {slope:.4f} per unit
- Start value: {values[0]:.2f}
- End value: {values[-1]:.2f}
- Total change: {values[-1] - values[0]:.2f} ({pct_change:+.1f}%)
- Data points: {n}"""

    return result
