import math
from typing import Union
import whr_core
from .base import Base


class Evaluate:
    def __init__(self, base: Base):
        """
        Tool to evaluate the performance the trained model of Elo ratings.

        Parameters
        ----------
        base : Base
            Trained model of Elo ratings.
        """
        self.core = whr_core.Evaluate(base.core)

    def get_rating(
        self, name: str, time_step: int, ignore_null_players: bool = True
    ) -> Union[float, None]:
        """
        Get the rating of a particular player at a particular time step.

        Parameters
        ----------
        name : str
            Name of the player.

        time_step : int
            Time step of the player.

        ignore_null_players : bool, default = True
            Ignore players not appearing in the database.
            If True, rating of null players will be set to None.
            If False, rating of null players will be set to 0.

        Returns
        -------
        float or None
            Rating of the requested player at the requested time step.
        """
        ret = self.core.get_rating(name, time_step, ignore_null_players)
        if not math.isfinite(ret):
            return None
        return ret

    def evaluate_ave_log_likelihood_games(
        self, games: list, ignore_null_players: bool = True
    ) -> float:
        """
        Compute the average log likelihood for the test dataset,
        which is a list of games.

        Parameters
        ----------
        games : list
            A list of games as the test dataset.
        Example:
        ```
        [('Carol', [[0, 103.91877749030998, 180.55812567296852], [60, 107.30695193277168, 183.1250043094528]]),
         ('Alice', [[0, 78.50976252870765, 185.55230942797314], [30, 79.47183295485291, 187.12327376311526]]),
         ('Bob', [[10, -15.262552175731392, 180.95086989932025], [60, -18.086030877782818, 183.0820052639819]]),
         ('Dave', [[10, -176.67739359273045, 201.15282077913983], [30, -177.3187738768273, 202.03179750776144]])]
         ```

        ignore_null_players : bool, optional
            Ignore players not appearing in the database.
            For each game, if there is a player not appearing the database,
            it will not be counted in the average log likelihood.

        Returns
        -------
        float
            Average log likelihood for the test dataset.
        """
        return self.core.evaluate_ave_log_likelihood_games(games, ignore_null_players)
