import logging
from typing import (
    Dict,
    List,
)

from model import Report
from model.exceptions import (
    ErrorBuildingReportData,
    ReportFileNotFound,
)
from nreports.build_report.dto import BuildReportRequest
from nreports.builders import DataBuilderFactory
from nreports.repository import I18N
from nreports_api.shared import JSON
from nreports_api.shared.report_dto import ReportDto

logger = logging.getLogger(name=__name__)


class BuildReportInteractor(object):

    def __init__(
        self,
        report_files: Dict[str, List[JSON]],
        data_builder_factory: DataBuilderFactory,
        i18n_repository: I18N,
    ) -> None:

        self.report_files = report_files
        self.data_builder_factory = data_builder_factory
        self.i18n_repository = i18n_repository

    def execute(
        self,
        request: BuildReportRequest,
    ) -> ReportDto:

        logger.info(msg=f"Report requested: {request.report_name}")

        report = self._get_report(report_name=request.report_name)

        data_to_build = report.get_data_to_build()

        data_builder = self.data_builder_factory.build(report_name=request.report_name)
        try:
            built_data = data_builder.build_data(
                data_to_build=data_to_build,
                **request.data,
            )
        except Exception as ex:
            raise ErrorBuildingReportData(
                report_name=request.report_name,
                error_message=str(ex),
            ) from ex

        formatted_report = report.format_data(
            built_data=built_data,
            i18n_repository=self.i18n_repository.build_i18n_repository(pos_id=request.pos_id or 0),
            l10n_repository=self.i18n_repository.build_l10n_repository(pos_id=request.pos_id or 0),
        )

        return ReportDto(formatted_report)

    def _get_report(
        self,
        report_name: str,
    ) -> Report:

        report = self.report_files.get(report_name.upper())
        if not report:
            raise ReportFileNotFound(report_name=report_name)

        return Report(report)
