"""Tool call dispatcher — maps tool names to handler functions."""
import asyncio
from ._helpers import _truncate_response
from .load_data import _handle_load_data
from .profile import _handle_profile_data
from .filter import _handle_filter_data
from .preprocess import _handle_preprocess_data
from .clustering import _handle_run_clustering, _handle_filter_and_cluster
from .evaluate import _handle_evaluate_clustering
from .features import _handle_extract_features
from .export import _handle_export_results
from .entities import _handle_build_entity_profiles, _handle_compute_scores
from .anomalies import _handle_detect_anomalies, _handle_visualize_anomalies
from .diagnostics import (
    _handle_validate_data, _handle_explore_distributions, _handle_find_outliers,
    _handle_diagnose_clustering, _handle_compare_datasets,
    _handle_export_debug_sample, _handle_repair_schema,
)
from .analysis import (
    _handle_analyze_patterns, _handle_analyze_temporal, _handle_analyze_fft,
    _handle_analyze_tls_health, _handle_analyze_geo_distribution,
    _handle_analyze_entity_detail,
)
from .data_mgmt import _handle_list_datasets, _handle_drop_dataset, _handle_clone_dataset
from .distance_matrix import _handle_compute_distance_matrix


async def handle_call(name: str, arguments: dict) -> dict:
    """Dispatch a tool call to the appropriate handler.

    Extracts the mandatory ``_timeout`` parameter (set by the LLM) from
    *arguments* and enforces it as an ``asyncio.wait_for`` deadline.

    Args:
        name: Tool name (must match one of the 30 tools).
        arguments: Tool-specific parameters, must include ``_timeout``.

    Returns:
        A JSON-serialisable dict.

    Raises:
        ValueError: If *name* is not a recognised tool.
    """
    _handlers = {
        'load_data': _handle_load_data,
        'profile_data': _handle_profile_data,
        'filter_data': _handle_filter_data,
        'preprocess_data': _handle_preprocess_data,
        'run_clustering': _handle_run_clustering,
        'evaluate_clustering': _handle_evaluate_clustering,
        'extract_features': _handle_extract_features,
        'export_results': _handle_export_results,
        'list_datasets': _handle_list_datasets,
        'drop_dataset': _handle_drop_dataset,
        'clone_dataset': _handle_clone_dataset,
        'build_entity_profiles': _handle_build_entity_profiles,
        'compute_scores': _handle_compute_scores,
        'filter_and_cluster': _handle_filter_and_cluster,
        'detect_anomalies': _handle_detect_anomalies,
        'visualize_anomalies': _handle_visualize_anomalies,
        'validate_data': _handle_validate_data,
        'explore_distributions': _handle_explore_distributions,
        'find_outliers': _handle_find_outliers,
        'diagnose_clustering': _handle_diagnose_clustering,
        'compare_datasets': _handle_compare_datasets,
        'export_debug_sample': _handle_export_debug_sample,
        'repair_schema': _handle_repair_schema,
        'analyze_patterns': _handle_analyze_patterns,
        'analyze_temporal': _handle_analyze_temporal,
        'analyze_fft': _handle_analyze_fft,
        'analyze_tls_health': _handle_analyze_tls_health,
        'analyze_geo_distribution': _handle_analyze_geo_distribution,
        'analyze_entity_detail': _handle_analyze_entity_detail,
        'compute_distance_matrix': _handle_compute_distance_matrix,
    }
    handler = _handlers.get(name)
    if handler is None:
        raise ValueError(f"Unknown tool: '{name}'")

    # Extract mandatory _timeout from the LLM-provided arguments
    timeout = arguments.pop('_timeout', 0)
    cleaned_args = arguments  # _timeout already removed by pop

    # Execute the handler with optional timeout
    if timeout and timeout > 0:
        try:
            result = await asyncio.wait_for(
                handler(**cleaned_args),
                timeout=timeout,
            )
        except asyncio.TimeoutError:
            result = {'error': f'工具 {name} 执行超时 ({timeout}秒)'}
    else:
        result = await handler(**cleaned_args)

    # Always ensure truncated key exists
    if 'truncated' not in result:
        result['truncated'] = False
    return _truncate_response(result)
