import json
from datetime import date, datetime
from decimal import Decimal
from backend.db_core import get_connection

def _json_serializer(obj):
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    if isinstance(obj, Decimal):
        return str(obj)
    raise TypeError(f"El tipo {type(obj)} no es serializable en JSON")

def registrar_auditoria(cursor, tabla, id_registro, accion, antes, despues, id_editor):
    query = """INSERT INTO utrau_auditoria_historica
    (tabla_afectada, id_registro, accion, datos_antes, datos_despues, id_usuario)
    VALUES (%s, %s, %s, %s, %s, %s)"""
    
    datos_antes_json = json.dumps(antes, default=_json_serializer)
    datos_despues_json = json.dumps(despues, default=_json_serializer)
    
    cursor.execute(query, (tabla, id_registro, accion, datos_antes_json, datos_despues_json, id_editor))

def actualizar_registro_seguro(tabla, id_registro, datos_nuevos, version_actual, id_editor):
    db = get_connection()
    cursor = db.cursor(dictionary=True)
    
    pk_name = 'id' 
    if tabla == "utrau_usuarios":
        pk_name = "id_usuario"
    
    try:
        cursor.execute(f"SELECT * FROM {tabla} WHERE {pk_name} = %s", (id_registro,))
        datos_antes = cursor.fetchone()
        
        if not datos_antes:
            return False

        set_clause = ", ".join([f"{k}=%s" for k in datos_nuevos.keys()])
        query = f"""UPDATE {tabla} SET {set_clause}, version = version + 1, id_editor = %s
                    WHERE {pk_name} = %s AND version = %s"""
        
        params = list(datos_nuevos.values()) + [id_editor, id_registro, version_actual]
        cursor.execute(query, params)
        
        if cursor.rowcount > 0:
            registrar_auditoria(cursor, tabla, id_registro, 'UPDATE', datos_antes, datos_nuevos, id_editor)
            db.commit()
            return True
        else:
            db.rollback()
            return False

    except Exception as e:
        db.rollback()
        raise e  
    finally:
        cursor.close()
        db.close()