import typing as ty

from nsj_gcf_utils.db_adapter2 import DBAdapter2

from nsj_rest_lib.dao.dao_base import DAOBase
from nsj_rest_lib.dto.dto_base import DTOBase
from nsj_rest_lib.entity.entity_base import EntityBase
from nsj_rest_lib.entity.function_type_base import (
    InsertFunctionTypeBase,
    UpdateFunctionTypeBase,
)
from nsj_rest_lib.injector_factory_base import NsjInjectorFactoryBase

from .service_base_delete import ServiceBaseDelete
from .service_base_get import ServiceBaseGet
from .service_base_insert import ServiceBaseInsert
from .service_base_save_by_function import ServiceBaseSaveByFunction
from .service_base_list import ServiceBaseList
from .service_base_partial_update import ServiceBasePartialUpdate
from .service_base_update import ServiceBaseUpdate


class ServiceBase(
    ServiceBaseSaveByFunction,
    ServiceBasePartialUpdate,
    ServiceBaseUpdate,
    ServiceBaseInsert,
    ServiceBaseDelete,
    ServiceBaseList,
    ServiceBaseGet,
):
    _dao: DAOBase
    _dto_class: ty.Type[DTOBase]

    def __init__(
        self,
        injector_factory: NsjInjectorFactoryBase,
        dao: DAOBase,
        dto_class: ty.Type[DTOBase],
        entity_class: ty.Type[EntityBase],
        dto_post_response_class: DTOBase = None,
        insert_function_type_class: ty.Optional[ty.Type[InsertFunctionTypeBase]] = None,
        update_function_type_class: ty.Optional[ty.Type[UpdateFunctionTypeBase]] = None,
    ):
        self._injector_factory = injector_factory
        self._dao = dao
        self._dto_class = dto_class
        self._entity_class = entity_class
        self._dto_post_response_class = dto_post_response_class
        self._created_by_property = "criado_por"
        self._updated_by_property = "atualizado_por"
        self._insert_function_type_class = None
        self._update_function_type_class = None
        self.set_insert_function_type_class(insert_function_type_class)
        self.set_update_function_type_class(update_function_type_class)

    @staticmethod
    def construtor1(
        db_adapter: DBAdapter2,
        dao: DAOBase,
        dto_class: ty.Type[DTOBase],
        entity_class: ty.Type[EntityBase],
        dto_post_response_class: DTOBase = None,
        insert_function_type_class: ty.Optional[ty.Type[InsertFunctionTypeBase]] = None,
        update_function_type_class: ty.Optional[ty.Type[UpdateFunctionTypeBase]] = None,
    ):
        """
        Esse construtor alternativo, evita a necessidade de passar um InjectorFactory,
        pois esse só é usado (internamente) para recuperar um db_adapter.

        Foi feito para não gerar breaking change de imediato (a ideia porém é, no futuro,
        gerar um breaking change).
        """

        class FakeInjectorFactory:
            def db_adapter(self):
                return db_adapter

        return ServiceBase(
            FakeInjectorFactory(),
            dao,
            dto_class,
            entity_class,
            dto_post_response_class,
            insert_function_type_class,
            update_function_type_class,
        )
