"""Public result objects for model selection analyses."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

import pandas as pd

from neuroweave.model_spec.model_spec import ModelSpec


@dataclass
class ModelComparisonResult:
    """Results of comparing multiple model specifications.

    Parameters
    ----------
    specs : list[ModelSpec]
        Specifications that were evaluated.
    scores : dict[str, float]
        Mapping from model labels to comparison scores.
    best_index : int | None, optional
        Index of the best-performing specification.
    metadata : dict[str, Any], optional
        Additional metadata describing the comparison run.
    """

    specs: list[ModelSpec] = field(default_factory=list)
    scores: dict[str, float] = field(default_factory=dict)
    best_index: int | None = None
    metadata: dict[str, Any] = field(default_factory=dict)

    def summary(self) -> str:
        """Summarize the model comparison results.

        Returns
        -------
        str
            Human-readable summary of comparison outcomes.
        """

        raise NotImplementedError()

    def best(self) -> ModelSpec:
        """Return the best-performing model specification.

        Returns
        -------
        ModelSpec
            Best-performing model specification.
        """

        raise NotImplementedError()

    def plot_scores(self) -> None:
        """Plot model comparison scores."""

        raise NotImplementedError()


@dataclass
class VariancePartitionResult:
    """Results of a variance-partition analysis.

    Parameters
    ----------
    unique : dict[str, float]
        Unique variance explained by each feature group.
    shared : float | None, optional
        Shared variance component across groups.
    full_score : float | None, optional
        Score of the full model.
    group_names : list[str], optional
        Ordered names of feature groups in the partition.
    lagwise : dict[str, Any] | None, optional
        Optional lag-wise variance contributions.
    """

    unique: dict[str, float] = field(default_factory=dict)
    shared: float | None = None
    full_score: float | None = None
    group_names: list[str] = field(default_factory=list)
    lagwise: dict[str, Any] | None = None

    def summary(self) -> str:
        """Summarize the variance partitioning results.

        Returns
        -------
        str
            Human-readable summary of variance contributions.
        """

        raise NotImplementedError()

    def plot(self) -> None:
        """Plot variance partitioning results."""

        raise NotImplementedError()

    def to_dataframe(self) -> pd.DataFrame:
        """Convert variance partitioning results to a tabular representation.

        Returns
        -------
        pandas.DataFrame
            Tabular view of the variance partitioning outputs.
        """

        raise NotImplementedError()


@dataclass
class AblationResult:
    """Results of a feature-ablation analysis.

    Parameters
    ----------
    feature_scores : dict[str, float]
        Scores obtained after ablating individual features.
    baseline_score : float | None, optional
        Score of the baseline full model.
    importance : dict[str, float], optional
        Derived feature-importance values.
    """

    feature_scores: dict[str, float] = field(default_factory=dict)
    baseline_score: float | None = None
    importance: dict[str, float] = field(default_factory=dict)

    def summary(self) -> str:
        """Summarize feature ablation results.

        Returns
        -------
        str
            Human-readable summary of feature importance.
        """

        raise NotImplementedError()

    def plot(self) -> None:
        """Plot feature-ablation results."""

        raise NotImplementedError()

    def rank_features(self) -> list[str]:
        """Return features ranked by ablation importance.

        Returns
        -------
        list[str]
            Features ordered by importance.
        """

        raise NotImplementedError()
