from openevalkit.score import Score
from openevalkit.scorers.base import Scorer
from openevalkit.run import Run
from openevalkit.errors import ScoringError

class ExactMatch(Scorer):
    """
    Checks if the output exactly matches the reference.

    Case-sensitive string comparison.
    
    Examples:
        >>> scorer = ExactMatch()
        >>> run = Run(id="1", input="2+2", output="4", reference="4")
        >>> score = scorer.score(run)
        >>> score.value
        True
        
        >>> run2 = Run(id="2", input="2+2", output="4", reference="5")
        >>> score2 = scorer.score(run2)
        >>> score2.value
        False
    """
    name = "exact_match"
    requires_reference = True
    cacheable = False

    def score(self, run: Run) -> Score:
        """
        Score by exact string equality.
        
        Args:
            run: Run to score
            
        Returns:
            Score with True if match, False otherwise
            
        Raises:
            ScoringError: If reference is missing
        """

        if run.reference is None: 
            raise ScoringError(
                f"{self.name} requires reference field. "
                f"Run {run.id} has no reference."
            )
        
        # Convert both to string for comparison
        output_str = str(run.output)
        reference_str = str(run.reference)

        matches = (output_str == reference_str)

        return Score(
            value=matches,
            reason="Match" if matches else "No match",
            metadata={
                "output_length": len(output_str),
                "reference_length": len(reference_str)
            }
        )
