import os
from dotenv import load_dotenv
from sqlalchemy import Column, Integer, String, Float, Boolean

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


from src.ConexionSql.Base_conexion import ConexionBase
from src.base import Base
from src.Llms.Modelos.Openai_model import ModeloOpenAI  # Clase real de lógica

# ----------------------
# Cargar clave maestra
# ----------------------
from entrypoint import ENV_PATH
load_dotenv(ENV_PATH)
pssword = os.getenv('MASTER_PASSWORD')
if pssword is None:
    raise ValueError("MASTER_PASSWORD no está definida en el archivo .env")

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

class ModeloOpenAIConfigModel(Base, Model_base):
    __tablename__ = 'modelo_openai_configs'

    id = Column(String, primary_key=True)

    model = Column(String, nullable=False)
    temperature = Column(Float, default=0.7, nullable=False)
    top_p = Column(Float, default=1.0, nullable=False)
    top_k = Column(Integer, nullable=True)

    frecuencia_penalizacion = Column(Float, default=0.0, nullable=False)
    num_tokens_maximos = Column(Integer, default=512, nullable=False)

    use_legacy = Column(Boolean, default=False, nullable=False)

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

class ModeloOpenAIConfigMapper(Mapper_base[ModeloOpenAI, ModeloOpenAIConfigModel]):

    @staticmethod
    def to_model(obj: ModeloOpenAI) -> ModeloOpenAIConfigModel:
        return ModeloOpenAIConfigModel(
            id=obj.id,
            model=obj.model,
            temperature=obj.temperature,
            top_p=obj.top_p,
            top_k=obj.top_k,
            frecuencia_penalizacion=obj.frecuencia_penalizacion,
            num_tokens_maximos=obj.num_tokens_maximos,
            use_legacy=obj.use_legacy
        )

    @staticmethod
    def from_model(model: ModeloOpenAIConfigModel, cliente: Optional[object] = None) -> ModeloOpenAI:
        return ModeloOpenAI(
            id=model.id,
            cliente=cliente,
            model=model.model,
            temperature=model.temperature,
            top_p=model.top_p,
            top_k=model.top_k,
            frecuencia_penalizacion=model.frecuencia_penalizacion,
            num_tokens_maximos=model.num_tokens_maximos,
            use_legacy=model.use_legacy
        )

    @staticmethod
    def to_dict(obj: ModeloOpenAI) -> dict:
        return {
            "id": obj.id,
            "model": obj.model,
            "temperature": obj.temperature,
            "top_p": obj.top_p,
            "top_k": obj.top_k,
            "frecuencia_penalizacion": obj.frecuencia_penalizacion,
            "num_tokens_maximos": obj.num_tokens_maximos,
            "use_legacy": obj.use_legacy
        }

    @staticmethod
    def from_dict(data: dict, cliente: Optional[object] = None) -> ModeloOpenAI:
        return ModeloOpenAI(
            id=data["id"],
            cliente=cliente,
            model=data["model"],
            temperature=data["temperature"],
            top_p=data["top_p"],
            top_k=data["top_k"],
            frecuencia_penalizacion=data["frecuencia_penalizacion"],
            num_tokens_maximos=data["num_tokens_maximos"],
            use_legacy=data["use_legacy"]
        )

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

class ModeloOpenAIConfigRepo(Repo_base[ModeloOpenAIConfigModel, ModeloOpenAI]):
    def __init__(self, conexion: ConexionBase, cliente: object):
        super().__init__(
            session=conexion.get_session(),
            modelo=ModeloOpenAIConfigModel,
            mapper=ModeloOpenAIConfigMapper
        )
        self.cliente = cliente  # Necesario para construir el dominio con lógica

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

    def get_all(self) -> list[ModeloOpenAI]:
        models = self.session.query(self.Modelo).all()
        return [self.Mapper.from_model(m, self.cliente) for m in models]