import os
from dotenv import load_dotenv
from sqlalchemy import Column, String
from sqlalchemy import Column, String, ForeignKey

from src.ArquitectureLayer.Mapper import Mapper_base
from src.ArquitectureLayer.Model import Model_base
from src.ArquitectureLayer.Repo import Repo_base

from src.ConexionSql.Base_conexion import ConexionBase
from src.base import Base
from src.Security.GenerarIDs import GeneradorIDUnico
from src.Llms.Embedders.Openai_embedder import OpenAIEmbedder
from src.ApiKeys.openai_apikey import OpenAICredencial

# ----------------------
# Cargar configuración desde .env si se requiere
# ----------------------
from entrypoint import ENV_PATH
load_dotenv(ENV_PATH)

# ----------------------
# MODELO (SQLAlchemy)
# ----------------------

class OpenAIEmbedderModel(Base, Model_base):
    __tablename__ = "openai_embedders"

    id = Column(String, primary_key=True)

    api_key_id = Column(String, ForeignKey("openai_credenciales.id"), nullable=False)
    model = Column(String, nullable=False)

# ----------------------
# MAPPER
# ----------------------

class OpenAIEmbedderMapper(Mapper_base[OpenAIEmbedder, OpenAIEmbedderModel]):

    @staticmethod
    def to_model(obj: OpenAIEmbedder) -> OpenAIEmbedderModel:
        return OpenAIEmbedderModel(
            id=obj.id,
            api_key_id=obj.client.credencial.id,
            model=obj.model
        )

    @staticmethod
    def from_model(model: OpenAIEmbedderModel, credencial: OpenAICredencial) -> OpenAIEmbedder:
        return OpenAIEmbedder(
            id=model.id,
            credencial=credencial,
            model=model.model
        )

    @staticmethod
    def to_dict(obj: OpenAIEmbedder) -> dict:
        return {
            "id": obj.id,
            "api_key_id": obj.client.credencial.id,
            "model": obj.model
        }

    @staticmethod
    def from_dict(data: dict, credencial: OpenAICredencial) -> OpenAIEmbedder:
        return OpenAIEmbedder(
            id=data["id"],
            credencial=credencial,
            model=data["model"]
        )

# ----------------------
# REPO
# ----------------------

class OpenAIEmbedderRepo(Repo_base[OpenAIEmbedderModel, OpenAIEmbedder]):
    def __init__(self, conexion: ConexionBase):
        super().__init__(
            session=conexion.get_session(),
            modelo=OpenAIEmbedderModel,
            mapper=OpenAIEmbedderMapper
        )

    def get_by_id(self, id_: str, credencial: OpenAICredencial) -> OpenAIEmbedder | None:
        model = self.session.get(self.Modelo, id_)
        return self.Mapper.from_model(model, credencial) if model else None

    def get_all(self, credencial_loader: callable) -> list[OpenAIEmbedder]:
        """
        :param credencial_loader: función que recibe un api_key_id y devuelve una instancia de OpenAICredencial
        """
        models = self.session.query(self.Modelo).all()
        return [
            self.Mapper.from_model(m, credencial_loader(m.api_key_id))
            for m in models
        ]