from typing import Any, Optional

from .. import base_metric, score_result


class Equals(base_metric.BaseMetric):
    """
    A metric that checks if an output string exactly matches an expected output string.

    This metric returns a score of 1.0 if the strings match exactly, and 0.0 otherwise.
    The comparison can be made case-sensitive or case-insensitive.

    Args:
        case_sensitive: Whether the comparison should be case-sensitive. Defaults to False.
        name: The name of the metric. Defaults to "equals_metric".
        track: Whether to track the metric. Defaults to True.
        project_name: Optional project name to track the metric in for the cases when there are no parent span/trace to inherit project name from.

    Example:
        >>> from opik.evaluation.metrics import Equals
        >>> equals_metric = Equals(case_sensitive=True)
        >>> result = equals_metric.score("Hello, World!", "Hello, World!")
        >>> print(result.value)
        1.0
        >>> result = equals_metric.score("Hello, World!", "hello, world!")
        >>> print(result.value)
        0.0
    """

    def __init__(
        self,
        case_sensitive: bool = False,
        name: str = "equals_metric",
        track: bool = True,
        project_name: Optional[str] = None,
    ):
        super().__init__(
            name=name,
            track=track,
            project_name=project_name,
        )
        self._case_sensitive = case_sensitive

    def score(
        self, output: Any, reference: Any, **ignored_kwargs: Any
    ) -> score_result.ScoreResult:
        """
        Calculate the score based on whether the output exactly matches the expected output.

        Args:
            output: The output to check. Will be converted to string for comparison.
            reference: The expected output to compare against. Will be converted to string for comparison.
            **ignored_kwargs: Additional keyword arguments that are ignored.

        Returns:
            score_result.ScoreResult: A ScoreResult object with a value of 1.0 if the values match,
                0.0 otherwise.
        """
        # Convert to string to handle numeric and other types
        output_str = str(output)
        reference_str = str(reference)

        value_left = output_str if self._case_sensitive else output_str.lower()
        value_right = reference_str if self._case_sensitive else reference_str.lower()

        if value_left == value_right:
            return score_result.ScoreResult(value=1.0, name=self.name)

        return score_result.ScoreResult(value=0.0, name=self.name)
