"""Feature contribution explanation for similarity comparison.

This module defines :class:`SimilarityExplanation`, which generates
an ordered list of feature identifiers that contribute most to the
difference between two MusicDNAVector objects.

The explanation layer operates exclusively on MusicDNAVector and
MusicDNALayout — it never requires MusicDNA objects.
"""

from __future__ import annotations

from music_dna.layout import MusicDNALayout
from music_dna.vector import MusicDNAVector


class SimilarityExplanation:
    """Generates feature contribution explanations for similarity.

    The explanation compares two vectors dimension-by-dimension,
    computes the absolute difference for each mapped feature, and
    returns the top-N feature identifiers sorted by largest
    difference.
    """

    @staticmethod
    def generate(
        a: MusicDNAVector,
        b: MusicDNAVector,
        layout: MusicDNALayout,
        top_n: int = 5,
    ) -> list[str]:
        """Generate an ordered list of top contributing features.

        Args:
            a: First MusicDNAVector.
            b: Second MusicDNAVector.
            layout: MusicDNALayout for index-to-feature mapping.
            top_n: Maximum number of features to return.

        Returns:
            List of feature identifiers sorted by largest absolute
            difference.  Ties are broken by feature identifier
            (alphabetical) for determinism.
        """
        contributions: list[tuple[float, str]] = []

        for identifier, index in layout.list_entries():
            diff = abs(float(a.values[index]) - float(b.values[index]))
            contributions.append((diff, identifier))

        contributions.sort(key=lambda x: (-x[0], x[1]))

        return [identifier for _, identifier in contributions[:top_n]]
