from abc import ABCMeta, abstractmethod
from typing import Iterable, Any, Tuple, Optional

from staff.lib.xlsx.view_row import ViewCell, ViewRow, Column, DataValidation


class SheetPresenter(metaclass=ABCMeta):
    """
    The presenter acts upon the model and the view.
    It retrieves data from repositories (the model), and formats it for display in the view.
    """

    sheet_name: Optional[str] = None
    """
    Sheet name displayed on excel tab for sheet. Also can be provided through __init__
    """
    outline_settings: dict = None
    freeze_panes: dict = None
    data_validations: Tuple[DataValidation] = ()

    def __init__(self, model: Iterable, sheet_name: str = None):
        """
        Model is the data access layer, which represents content. The model is an interface
        defining the data to be displayed
        """
        if sheet_name is not None:
            self.sheet_name = sheet_name
        self._model = model

    @abstractmethod
    def rows(self) -> Iterable[ViewRow]:
        pass

    def default_view_rows_from_data_model(self):
        """
        Shortcut for converting each item in model into ViewRow using default values for ViewRow and ViewCell
        """
        for model_row in self._model:
            yield ViewRow(SheetPresenter.default_view_cells_from_row_data(model_row))

    @staticmethod
    def default_view_row_from_row_data(model_row: Iterable[Any]) -> ViewRow:
        return ViewRow(SheetPresenter.default_view_cells_from_row_data(model_row))

    @staticmethod
    def default_view_cells_from_row_data(model_row: Iterable[Any]) -> Iterable[ViewCell]:
        return (
            item if isinstance(item, ViewCell) else ViewCell(text=item)
            for item in model_row
        )

    @abstractmethod
    def columns(self) -> Iterable[Column]:
        raise NotImplementedError()

    @staticmethod
    def auto_columns() -> Iterable[Column]:
        """
        Shortcut method, use it inside columns method when do not want to define your custom columns
        """
        return []
