from typing import List

import hydra

from ltsgns_mp.algorithms.abstract_algorithm import AbstractAlgorithm
from ltsgns_mp.recording.loggers import get_loggers
from ltsgns_mp.recording.loggers.abstract_logger import AbstractLogger
from ltsgns_mp.recording.loggers.logger_util.get_logging_writer import get_logging_writer
from ltsgns_mp.util import keys
from ltsgns_mp.util.own_types import ValueDict, ConfigDict


class Recorder:
    """
    Records the algorithm whenever called by computing common recording values and then delegating the
    recording itself to different recorders.
    """

    def __init__(self, config: ConfigDict,
                 algorithm: AbstractAlgorithm):
        """
        Initialize the recorder, which itself is an assortment of loggers
        Args:
            config: full config of the whole project
            algorithm:
        """
        self._loggers: List[AbstractLogger] = get_loggers(config=config, algorithm=algorithm)
        self._algorithm = algorithm
        self._writer = get_logging_writer(self.__class__.__name__,
                                          recording_directory=hydra.core.hydra_config.HydraConfig.get().runtime.output_dir)

    def record_iteration(self, iteration: int, recorded_values: ValueDict) -> ValueDict:
        self._writer.info("Recording iteration {}".format(iteration))

        for logger in self._loggers:
            # try:
            logger.log_iteration(recorded_values=recorded_values,
                                 iteration=iteration)
            # except Exception as e:
            #     self._writer.error("Error with logger '{}': {}".format(logger.__class__.__name__, repr(e)))
        self._writer.info("Finished recording iteration {}\n".format(iteration))
        scalars = recorded_values.get(keys.SCALARS, {})
        return scalars

    def finalize(self) -> None:
        """
        Finalizes the recording by asking all loggers to finalize. The loggers may individually save things to disk or
        postprocess results.
        Returns:

        """
        self._writer.info("Finished experiment! Finalizing recording")
        for logger in self._loggers:
            logger.finalize()
            logger.remove_writer()

        self._writer.info("Finalized recording.")
        self._writer.handlers = []
        del self._writer
