"""
Servicio de identidad: validación de cédula, parseo de fechas y caché de datos de usuario en Redis.
"""
import json as json_mod
import logging

from langchain_openai import ChatOpenAI
from config.settings import settings

logger = logging.getLogger(__name__)

USER_IDENTITY_TTL = 1800  # 30 minutos para datos de identidad compartidos entre flujos

_DATE_PARSE_PROMPT = """Extrae la fecha de nacimiento del siguiente texto y conviértela EXACTAMENTE al formato dd-MM-yyyy.

Reglas:
- Si el año tiene 2 dígitos, asume siglo 1900 si >= 30, siglo 2000 si < 30 (ej: 97 → 1997, 05 → 2005).
- Responde ÚNICAMENTE con la fecha en formato dd-MM-yyyy (ejemplo: 25-07-1997).
- Si no puedes identificar una fecha válida, responde exactamente: INVALID

Texto del usuario: {user_input}"""

_llm = ChatOpenAI(model=settings.MODEL_NAME, temperature=0)


class IdentityService:
    """Validación de identidad y caché de datos de usuario en Redis."""

    def validate_cedula(self, cedula: str) -> bool:
        """
        Valida una cédula ecuatoriana usando el algoritmo de módulo 10.
        Retorna True si la cédula es válida, False en caso contrario.
        """
        if not cedula.isdigit() or len(cedula) != 10:
            return False

        provincia = int(cedula[:2])
        if provincia < 1 or (provincia > 24 and provincia != 30):
            return False

        tercer_digito = int(cedula[2])
        if tercer_digito > 5:
            return False

        coeficientes = [2, 1, 2, 1, 2, 1, 2, 1, 2]
        suma = 0
        for i in range(9):
            valor = int(cedula[i]) * coeficientes[i]
            if valor > 9:
                valor -= 9
            suma += valor

        residuo = suma % 10
        digito_verificador = 0 if residuo == 0 else 10 - residuo

        return digito_verificador == int(cedula[9])

    def parse_date(self, user_input: str) -> str | None:
        """
        Usa el LLM para normalizar una fecha en lenguaje natural a dd-MM-yyyy.
        Retorna la fecha formateada o None si no se pudo parsear.
        """
        try:
            response = _llm.invoke(_DATE_PARSE_PROMPT.format(user_input=user_input))
            parsed = response.content.strip()
            if parsed == "INVALID":
                return None
            parts = parsed.split("-")
            if len(parts) == 3 and len(parts[0]) == 2 and len(parts[1]) == 2 and len(parts[2]) == 4:
                return parsed
            return None
        except Exception as e:
            logger.error(f"Error parseando fecha con LLM: {e}")
            return None

    async def load_identity(self, redis_client, uuid: str) -> dict:
        """Carga los datos de identidad cacheados para un usuario desde Redis."""
        USER_IDENTITY_KEY = f"user_identity:{uuid}"
        identity_raw = await redis_client.get(USER_IDENTITY_KEY)
        return json_mod.loads(identity_raw) if identity_raw else {}

    async def save_identity(
        self,
        redis_client,
        uuid: str,
        cedula: str,
        fecha_nacimiento: str | None = None,
    ) -> None:
        """Persiste los datos de identidad en Redis con TTL."""
        USER_IDENTITY_KEY = f"user_identity:{uuid}"
        identity_data: dict = {"cedula": cedula}
        if fecha_nacimiento:
            identity_data["fecha_nacimiento"] = fecha_nacimiento
        await redis_client.setex(USER_IDENTITY_KEY, USER_IDENTITY_TTL, json_mod.dumps(identity_data))
        logger.info(f"🔑 [{uuid}] Identidad guardada: cédula={cedula}")
