"""evaluate_clustering handler — compute clustering quality metrics."""
from typing import Optional
from analysis.constants import RANDOM_SEED

import numpy as np
import polars as pl

from ..session_store import SessionStore


async def _handle_evaluate_clustering(
    cluster_result_id: str,
    dataset_id: str,
    metrics: Optional[list[str]] = None,
) -> dict:
    """Evaluate clustering result against the dataset."""
    store = SessionStore()
    cluster_entry = store.get_cluster_result(cluster_result_id)
    if cluster_entry is None:
        return {'error': f'Cluster result not found: {cluster_result_id}',
                'truncated': False}

    dataset_entry = store.get_dataset(dataset_id)
    if dataset_entry is None:
        return {'error': f'Dataset not found: {dataset_id}', 'truncated': False}

    labels = cluster_entry['labels']
    default_metrics = ['silhouette', 'davies_bouldin', 'calinski_harabasz',
                       'noise_ratio', 'cluster_sizes']
    requested = metrics or default_metrics

    scores: dict = {'n_clusters': cluster_entry['n_clusters']}

    lf: pl.LazyFrame = dataset_entry['lazyframe']
    params = cluster_entry.get('params', {})
    feature_cols = params.get('feature_columns', [])
    if not feature_cols and 'feature_columns' in params:
        pass
    elif feature_cols:
        df_features = lf.select(feature_cols).collect(streaming=True)
        data = df_features.to_numpy()

        # Align labels with data (handle missing rows)
        valid_mask = ~np.isnan(data).any(axis=1) if data.dtype.kind == 'f' else np.ones(len(data), dtype=bool)
        data_clean = data[valid_mask]
        labels_clean = np.array(labels)[:len(data_clean)]

        unique_labels = set(labels_clean)
        n_clusters_actual = len(unique_labels - {-1})

        for m in requested:
            if m == 'silhouette' and n_clusters_actual >= 2:
                from sklearn.metrics import silhouette_score
                scores['silhouette'] = round(float(
                    silhouette_score(data_clean, labels_clean, random_state=RANDOM_SEED)), 4)
            elif m == 'davies_bouldin' and n_clusters_actual >= 2:
                from sklearn.metrics import davies_bouldin_score
                scores['davies_bouldin'] = round(float(
                    davies_bouldin_score(data_clean, labels_clean)), 4)
            elif m == 'calinski_harabasz' and n_clusters_actual >= 2:
                from sklearn.metrics import calinski_harabasz_score
                scores['calinski_harabasz'] = round(float(
                    calinski_harabasz_score(data_clean, labels_clean)), 4)
            elif m == 'noise_ratio':
                noise = int((labels_clean == -1).sum())
                scores['noise_ratio'] = round(noise / len(labels_clean), 4)
            elif m == 'cluster_sizes':
                sizes = {}
                for label in unique_labels:
                    sizes[int(label)] = int((labels_clean == label).sum())
                scores['cluster_sizes'] = sizes

    scores['n_clusters'] = cluster_entry['n_clusters']


    return {'scores': scores}
