# src\ArquitectureLayer\Mapper.py

from abc import ABC, abstractmethod
from typing import TypeVar, Generic, Type
import json

TDominio = TypeVar("TDominio")
TModelo = TypeVar("TModelo")

class Mapper_base(ABC, Generic[TDominio, TModelo]):
    # ----------------------------
    # Conversiones individuales
    # ----------------------------

    @staticmethod
    @abstractmethod
    def to_model(obj: TDominio) -> TModelo:
        """Convierte objeto de dominio a modelo ORM"""
        pass

    @staticmethod
    @abstractmethod
    def from_model(model: TModelo) -> TDominio:
        """Convierte modelo ORM a objeto de dominio"""
        pass

    @staticmethod
    @abstractmethod
    def to_dict(obj: TDominio) -> dict:
        """Convierte objeto de dominio a diccionario plano"""
        pass

    @staticmethod
    @abstractmethod
    def from_dict(d: dict) -> TDominio:
        """Convierte diccionario plano a objeto de dominio"""
        pass

    @classmethod
    def to_json(cls, obj: TDominio) -> str:
        """Convierte objeto de dominio a JSON string"""
        return json.dumps(cls.to_dict(obj), default=str)

    @classmethod
    def from_json(cls, json_str: str) -> TDominio:
        """Convierte JSON string a objeto de dominio"""
        return cls.from_dict(json.loads(json_str))

    # ----------------------------
    # Conversiones en lote (bulk)
    # ----------------------------

    @classmethod
    def to_model_list(cls, objs: list[TDominio]) -> list[TModelo]:
        return [cls.to_model(o) for o in objs]

    @classmethod
    def from_model_list(cls, models: list[TModelo]) -> list[TDominio]:
        return [cls.from_model(m) for m in models]

    @classmethod
    def to_dict_list(cls, objs: list[TDominio]) -> list[dict]:
        return [cls.to_dict(o) for o in objs]

    @classmethod
    def from_dict_list(cls, dicts: list[dict]) -> list[TDominio]:
        return [cls.from_dict(d) for d in dicts]

    @classmethod
    def to_json_list(cls, objs: list[TDominio]) -> str:
        return json.dumps(cls.to_dict_list(objs), default=str)

    @classmethod
    def from_json_list(cls, json_str: str) -> list[TDominio]:
        return cls.from_dict_list(json.loads(json_str))