
import json
from configuraciones import variables

# Cargar variables de entorno ANTES de importar cosas que las necesiten
env_path = variables.variables_entorno()

from fastapi import Body, FastAPI, Form, Request, Response, Query, HTTPException, UploadFile, File, Cookie, WebSocket, WebSocketDisconnect, Depends
from typing import List, Optional
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import logging
import requests
from typing import Dict


# Importaciones de los diferentes módulos
from login import login
from administracion import mailing
from administracion import my_profile
from administracion import profiling
from administracion import account
from administracion import employee
from administracion import help_desk
from administracion import statistics
from personas import contactos
from configuraciones import general_information
from soporte import soporte
from soporte import mailing_support
from procesos import contactabilidad
from procesos import encuestas
from procesos import primer_contacto
from procesos import noticias
from procesos import malling_primer_contacto
from procesos import marketing
from procesos import admin_propuestas
from asistente import api_ia
from procesos import campanas
from procesos import descartados
from dashboard import kpis
from procesos import tareas




# Importar clases para endpoints POST y PUT
from clases import LoginRequest, NuevoContactoRequest, ActualizarNoticiaRequest, adjuntoFidelizacion, codigoTemporalRequest, EnviarCorreoEmpleadoRequest, ActualizarPerfilRequest, ListProspectosRequest, ListProspectosResponse, ActualizarContraseñaRequest, NuevoPermisoRequest, ActualizarPermisoRequest, ActualizarEmpleadoRequest, ActualizarGeneralInformationRequest, NuevoCuentaServicioRequest, actualizarCuentaServicioRequest, CuentaRequest, CuentaServicioRequest, actualizarCuentadeServicioRequest, ActualizarMesaAyudaRequest, SoporteDataRequest, EnviarCorreoSoporteRequest, NuevoEmpleadoRequest, ActualizarEmpleadoPerfilRequest, NuevoPerfilRequest, ListEncuestadosRequest, ListEncuestadosResponse, TablaSeleccionadaRequest, TablaSeleccionadaResponse, TablaSeleccionadaResponse, CreateNotesResponse, CreateNotesRequest, VoluntarioUpdateRequest, PrimerContactoRequest,EnviarCorreoRequest, updateContacto, NuevoAreaRequest, NuevoCargoRequest, ActualizarAreaRequest, ActualizarCargoRequest, verificacionContactadoRequest, actualizarEstadoEtapaRequest, AssistantsInstructionRequest, agregarNuevoProspectoRequest, ObtenerRecordatoriosRequest, ObtenerUrlFirmadaRequest, ObtenerUrlFirmadaResponse, ObtenerUrlFirmadaError, ObtenerPropuestasCrmRequest, ObtenerPropuestasCrmResponse, ObtenerPropuestasCrmError, ProcesamientoResponse, ProcesamientoError, TablaSeleccionadaMarketingRequest, BusquedaPorCamposDinamicosRequest, ActualizarEstadoEtapa, NuevaEncuestaRequest, NuevaPreguntaRequest, NuevaRespuestaRequest, TiempoSesionRequest, AssistantsEmpresaRequest, ActualizarDatosAsistente, NuevaCampanaRequest, ActualizarRespuestaRequest, ActualizarPreguntaRequest, ActualizarEncuestaRequest, EnvioMailRequest, UserAssignedContactedRequest, UserAssignedContactedResponse, ListRejectedRequest, ListRejectedResponse, ParamsUpdateData, EnviarCorreoEmpleadoRequest2, EnviarCorreoContactoRequest, EnvioMailContactRequest, GetEmailTemplateResponse, GetEmailTemplateRequest, ActualizarPlantillaCorreoRequest



# Crear la instancia de la aplicación FastAPI
app = FastAPI(debug=True)

# Configurar CORS para permitir solicitudes desde los orígenes necesarios
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        'http://localhost:3000',
        'http://localhost:4200',
        'https://crm.imparables.com.co',
        "https://dev.crm.imparables.cic-ware.com",
        'https://pru.crm.imparables.com.co',
        'https://pru.imparables.com.co',
        'https://dev.crm.imparables.com.co',
    ],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Configurar logging para capturar y mostrar errores
logging.basicConfig(level=logging.INFO)





""" ======================= Peticiones GET ======================= """
@app.get("/ask/consultarCargos")
async def get_cargos():
    return my_profile.consultarCargos()



@app.get("/ask/consultarPermisos/{id_perfil}")
async def consultar_permisos(id_perfil: int):
    return profiling.consultarPermisos(id_perfil)



@app.get("/ask/consultarPermisosVistas/{idPerfil}")
async def consultar_permisos_vistas(idPerfil: int):
    return profiling.consultarPermisosVistas(idPerfil)



@app.get("/ask/consultarElementosPerfil/{id_perfil}")
async def consultar_elementos_perfil(id_perfil: int):
    return profiling.consultarPermisosElementos(id_perfil)



@app.get("/ask/consultarElementos/{id_vista}")
async def consultar_elementos(id_vista: int):
    return profiling.consultarElementos(id_vista)



@app.get("/ask/consultarPerfil")
async def consultar_Perfil():
    return profiling.consultarPerfil()



@app.get("/ask/consultarModulos")
async def consultar_modulos():
    return profiling.consultarModulos()



@app.get("/ask/consultarVistas/{id_modulo}")
async def consultar_vistas(id_modulo: int):
    return profiling.consultarVistas(id_modulo)



@app.get("/ask/consultarPerfil")
async def consultar_Perfil():
    return profiling.consultarPerfil()



@app.get("/ask/consultarCargosByArea/{idArea}")
async def consultar_cargos_by_area(idArea: int):
    return my_profile.consultarCargosByAreas(idArea)



@app.get("/ask/consultarArea")
async def consultar_areas():
    return my_profile.consultarAreas()



@app.get("/ask/consultarGeneralInformation")
async def consultar_gen_info():
    return general_information.consultarGenInfo()



@app.get("/ask/recuperarSoporte/{idEmployee}")
async def recuperar_soporte(idEmployee: int):
    return soporte.recuperarSoporte(idEmployee)



@app.get("/ask/getModulos")
async def get_modulos():
    return soporte.getModulos()



@app.get("/ask/getVistas/{id_modulo}")
async def get_vistas(id_modulo: int):
    return soporte.getVistas(id_modulo)



@app.get("/ask/getTickets/{idEmployee}")
async def consultar_tickets_por_empleado(idEmployee: int):
    return soporte.getTickets(idEmployee)



@app.get("/ask/getListaTablasDB")
async def get_lista_tablas_DB():
    return contactabilidad.getListaTablas()

@app.get("/ask/tareasDisponiblesPrimerContacto")
async def get_tareas_disponibles():
    return primer_contacto.getTareasPrimerContacto()


@app.get("/ask/tareasDisponibles")
async def get_tareas_disponibles():
    return primer_contacto.getTareasDisponibles()


@app.get("/ask/consultarNotasContacto/{id}")
async def consultar_notas_contacto(id: int):
    try:
        return contactabilidad.getNotesContact({"id_contacto_origen": id})
    except Exception as e:
        logging.error(f"Error al consultar las notas de contacto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de consulta de notas de contacto")


@app.get("/ask/logSftpConfig")
async def log_sftp_config():
    return noticias.log_sftp_configuration()





@app.get("/ask/tablasSegunContacto/{tipo_contacto}")
async def consultar_notas_contacto(tipo_contacto: str):
    try:
        return marketing.get_lista_tablas_tipo_contacto(tipo_contacto)
    except Exception as e:
        logging.error(f"Error al consultar las tablas segun el tipo de contacto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de consulta de las tablas segun el tipo de contacto")



# Paso 3 - Columnas obligatorias en la BD
@app.get(
    "/ask/procesamientoExcel/prospectos/paso3/columnasObligatorias",
    response_model=ProcesamientoResponse,
    responses={400: {"model": ProcesamientoError}, 500: {"model": ProcesamientoError}},
    tags=["Procesamiento Excel - Prospectos"],
)
async def endpoint_paso_3():
    try:
        resultado = await contactabilidad.procesamiento_principal_paso_3_obtener_columnas_obligatorias_base_de_datos()
        if not resultado.get("success", False):
            raise HTTPException(status_code=400, detail=resultado.get("message", "Error al obtener columnas obligatorias"))
        return ProcesamientoResponse(success=True, message=resultado.get("message", ""), data=resultado.get("data"))
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error en paso 3: {e}")
        raise HTTPException(status_code=500, detail="Error interno")


# Paso 4 - Columnas opcionales en la BD
@app.get(
    "/ask/procesamientoExcel/prospectos/paso4/columnasOpcionales",
    response_model=ProcesamientoResponse,
    responses={400: {"model": ProcesamientoError}, 500: {"model": ProcesamientoError}},
    tags=["Procesamiento Excel - Prospectos"],
)
async def endpoint_paso_4():
    try:
        resultado = await contactabilidad.procesamiento_principal_paso_4_obtener_columnas_opcionales_base_de_datos()
        if not resultado.get("success", False):
            raise HTTPException(status_code=400, detail=resultado.get("message", "Error al obtener columnas opcionales"))
        return ProcesamientoResponse(success=True, message=resultado.get("message", ""), data=resultado.get("data"))
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error en paso 4: {e}")
        raise HTTPException(status_code=500, detail="Error interno")




@app.get("/ask/obtenerRespuestasPrimerContacto/{id}")
def obtener_respuestas_primer_contacto(id: int):
    try:
        return contactos.get_respuestas_primer_contacto(id)
    except Exception as e:
        logging.error(f"Error al obtener las respuestas del primer contacto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de respuestas del primer contacto")



@app.get("/ask/estadosEtapas")
async def consultar_estados_etapas():
    try:
        return marketing.traer_estados_etapas()
    except Exception as e:
        logging.error(f"Error al consultar los estados etapas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de consulta de estados etapas")



@app.get("/ask/consultarEncuestas")
async def consultar_encuestas():
    try:
        return encuestas.traer_lista_encuestas()
    except Exception as e:
        logging.error(f"Error al consultar Encuestas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de consultar encuestas")



@app.get("/ask/consultarTiposPreguntas")
async def consultar_tipos_preguntas_encuestas():
    try:
        return encuestas.traer_tipos_preguntas()
    except Exception as e:
        logging.error(f"Error al obtener la información de los tipos de preguntas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.get("/ask/consultarCategorias")
async def consultar_tipos_preguntas_encuestas():
    try:
        return encuestas.traer_categorias_encuestas()
    except Exception as e:
        logging.error(f"Error al obtener la información de las categorias de las encuestas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.get("/ask/statistics/inscripciones-voluntarios")
async def get_inscripciones_voluntarios_statistics():
    """Obtener estadísticas de Inscripciones Voluntarios"""
    return statistics.get_inscripciones_voluntarios_stats()


@app.get("/ask/statistics/registros-crm-antiguo")
async def get_registros_crm_antiguo_statistics():
    """Obtener estadísticas de Registros CRM Antiguo"""
    return statistics.get_registros_crm_antiguo_stats()


@app.get("/ask/statistics/base-datos-10k")
async def get_base_datos_10k_statistics():
    """Obtener estadísticas de Base de Datos 10k"""
    return statistics.get_base_datos_10k_stats()


@app.get("/ask/statistics/prospectos-manual")
async def get_prospectos_manual_statistics():
    """Obtener estadísticas de Prospectos Manual"""
    return statistics.get_prospectos_manual_stats()


@app.get("/ask/statistics/contactability/all")
async def get_all_contactability_statistics():
    """Obtener todas las estadísticas de contactabilidad"""
    return statistics.get_all_contactability_stats()


@app.get("/ask/statistics/contactability/summary")
async def get_contactability_summary_statistics():
    """Obtener resumen consolidado de estadísticas de contactabilidad"""
    return statistics.get_contactability_summary()


@app.get("/ask/statistics/dashboard")
async def get_dashboard_statistics():
    """Obtener estadísticas para el dashboard principal"""
    return statistics.get_contactability_summary()



@app.get("/ask/consultarPreguntas/{id_enc}")
async def consultar_preguntas_encuestas(id_enc: int):
    try:
        return encuestas.traer_lista_preguntas(id_enc)
    except Exception as e:
        logging.error(f"Error al consultar preguntas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de consulta preguntas")


@app.get("/ask/consultarRespuesta/{id_enc_det}")
async def consultar_notas_contacto(id_enc_det: int):
    try:
        return encuestas.traer_lista_respuestas(id_enc_det)
    except Exception as e:
        logging.error(f"Error al consultar las respuestas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de consultar respuestas")



@app.get("/ask/statistics/prospectos/ciudades")
async def get_prospectos_ciudades_statistics():
    """Obtener estadísticas de prospectos por ciudad"""
    return statistics.get_prospectos_por_ciudad()

@app.get("/ask/statistics/prospectos/detalle-tablas")
async def get_prospectos_detalle_tablas_statistics():
    """Obtener detalle de prospectos por tabla y ciudad"""
    return statistics.get_prospectos_detalle_por_tabla()

@app.get("/ask/statistics/prospectos/top-ciudades/{limite}")
async def get_top_ciudades_prospectos_statistics(limite: int = 10):
    """Obtener top ciudades con más prospectos"""
    return statistics.get_top_ciudades_prospectos(limite)

@app.get("/ask/statistics/prospectos/top-ciudades")
async def get_top_ciudades_prospectos_default():
    """Obtener top 10 ciudades con más prospectos (por defecto)"""
    return statistics.get_top_ciudades_prospectos(10)

@app.get("/ask/statistics/union-contacto-personas")
async def get_union_contacto_personas_statistics():
    """Obtener estadísticas por estado de etapa de union_contacto_personas"""
    return statistics.get_union_contacto_personas_stats()

@app.get("/ask/statistics/union-contacto-personas/resumen")
async def get_union_contacto_personas_resumen_statistics():
    """Obtener resumen consolidado de union_contacto_personas"""
    return statistics.get_union_contacto_personas_resumen()


@app.get("/ask/listAssistants")
async def list_assistants():
    return api_ia.listAssistants()

@app.post("/ask/instrucciones")
async def get_assistants_instructions(request: AssistantsInstructionRequest):
    try:
        data = {
            "idAsistente": request.id_asistente
        }
        return api_ia.obtener_instrucciones_asistentes(data)

    except Exception as e:
        logging.error(f"Error al obtener instrucciones : {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la")

@app.get("/ask/statistics/descriptivas/consolidadas")
async def get_estadisticas_descriptivas_consolidadas_endpoint():
    """Obtener estadísticas descriptivas consolidadas de las 4 tablas"""
    return statistics.get_estadisticas_descriptivas_consolidadas()

@app.get("/ask/statistics/descriptivas/por-tabla")
async def get_estadisticas_descriptivas_por_tabla_endpoint():
    """Obtener estadísticas descriptivas de cada tabla por separado"""
    return statistics.get_estadisticas_descriptivas_por_tabla()



@app.get("/ask/primer_contacto")
async def obtener_logs_primer_contacto():
    return statistics.get_logs_primer_contacto_summary()



@app.get("/ask/contactos-kpis")
async def obtener_contactos_kpis():
    return kpis.getContactosKPIs()




@app.get("/ask/descartados")
async def consultar_descartados(
    fecha: Optional[str] = None
):
    # Crear el objeto request
    request_data = ListRejectedRequest(
        fecha=fecha
    )
    
    resultado = descartados.obtener_descartados(request_data)
    if not resultado["success"]:
        raise HTTPException(status_code=500, detail=resultado["message"])
    return resultado



@app.get("/ask/Alltareas")
async def list_tareas_endpoint():
    try:
        return tareas.get_tareas()
    except Exception as e:
        logging.error(f"Error al consultar tareas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de consulta tareas")



""" ======================= Peticiones POST ======================= """
@app.post("/ask/variablesEntorno")
async def variables_entorno():
    return variables.variables_entorno()



@app.post("/ask/obtenerCuentasServicio")
async def obtenerCuentas():
    return account.obtenerCuentas()



@app.post("/ask/users")
async def get_users():
    return employee.listEmpleados()

@app.post("/ask/obtenerNoticiasCrm")
async def obtener_noticiascrm(fecha: Optional[str] = Query(None, description="Fecha en formato YYYY-MM-DD")):
    return noticias.obtener_noticiascrm(fecha)


#Insertar Campaña 
@app.post("/ask/insertarCampana")
async def insertar_campana(request: NuevaCampanaRequest):
    try:
        data = {
            "nombre_campana": request.nombre_campana,
            "mensaje_campana": request.mensaje_campana,
            "id_empleado": request.id_empleado,
            "medio_envio": request.medio_envio,
            "fecha_creacion": request.fecha_creacion
        }
        # Aquí llamas a tu capa de persistencia (ejemplo: profiling.insertarCampana)
        return campanas.insertarCampana(data)
    except Exception as e:
        logging.error(f"Error al insertar la campaña: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción de la campaña")

@app.post("/ask/insertarNoticiasCrm", response_model=dict, responses={200: {"model": dict}}, tags=["Agregar nueva propuesta"])
async def insertar_noticia_crm(
    principal: str = Form(...),
    fecha_noticia: str = Form(...),
    titulo: str = Form(...),
    link: str = Form(...),
    texto_corto: str = Form(...),
    texto_largo: str = Form(...),
    id_estado: int = Form(...),
    adjunto: UploadFile = File(...)
):
    try:
        # Los datos del formulario ya están disponibles como variables individuales
        data = {
            'principal': principal,
            'fecha_noticia': fecha_noticia,
            'titulo': titulo,
            'link': link,
            'texto_corto': texto_corto,
            'texto_largo': texto_largo,
            'id_estado': id_estado,
            'adjunto': adjunto
        }
        
        # Ahora puedes llamar a la función que maneja la inserción
        resultado = noticias.insertar_noticia(data)
        return resultado

    except HTTPException as e:
        raise e
    except Exception as e:
        logging.error(f"Error al insertar noticia in main: {e}")
        raise HTTPException(status_code=500, detail="Error interno al insertar noticia")

    

@app.post("/ask/obtenerDataMesaAyuda")
async def obtener_datos_mesa_ayuda():
    return help_desk.obtenerDatosMesaAyuda()



@app.post("/ask/login")
async def login_route(request: LoginRequest):  # Usar la clase LoginRequest en lugar de los parámetros individuales
    try:
        data = {
            "email": request.email,
            "password": request.password
        }
        # Pasar los datos al método de login
        return login.login(data)  # Cambia esto por la lógica real de login
    except Exception as e:
        logging.error(f"Error en login: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de login")



@app.post("/ask/codigo")
async def codigo_temporal(request: codigoTemporalRequest):
    try:
        data = {
            "email": request.email
        }
        # Pasar los datos al método de obtener asistentes
        return login.codigoTemporal(data)
    except Exception as e:
        logging.error(f"Error al obtener asistentes: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de obtener asistentes")




@app.post("/ask/envioMail")
async def envioMail(request: EnvioMailRequest):
    try:
        # Normalizar destinatarios a lista
        if isinstance(request.destinatario, str):
            destinatarios = [request.destinatario.strip()] if request.destinatario.strip() else []
        else:
            destinatarios = [email.strip() for email in request.destinatario if email.strip()]
        
        # Preparar data para sendEmail
        data = {
            "destinatario": destinatarios,  # Enviar como lista
            "asunto": request.asunto,
            "cuerpo_correo": request.cuerpo_correo
        }
        
        # Llamar a la función de envío
        resultado_envio = mailing.sendEmail_marketing(data)
        
        # Si hay envíos exitosos, registrar logs
        destinatarios_exitosos = []
        if resultado_envio.get("success"):
            destinatarios_exitosos = resultado_envio.get("destinatarios_exitosos", [])
            
            # Si no viene la lista detallada, inferirla del resultado
            if not destinatarios_exitosos:
                errores_count = resultado_envio.get("errores_count", 0)
                if errores_count == 0:
                    # Todos fueron exitosos
                    destinatarios_exitosos = destinatarios
                else:
                    # Calcular exitosos basado en errores detallados
                    errores_detallados = resultado_envio.get("detalles_errores", [])
                    destinatarios_con_error = {error["destinatario"] for error in errores_detallados}
                    destinatarios_exitosos = [dest for dest in destinatarios if dest not in destinatarios_con_error]
        
        # Registrar logs solo para envíos exitosos
        if destinatarios_exitosos:
            resultado_logs = mailing.registrar_logs_envio(destinatarios_exitosos, request.id_campana)
            
            # Agregar información de logs al resultado
            resultado_envio["logs_registrados"] = resultado_logs.get("success", False)
            if resultado_logs.get("success"):
                resultado_envio["logs_count"] = resultado_logs.get("registros", 0)
            else:
                resultado_envio["logs_error"] = resultado_logs.get("message")
        else:
            resultado_envio["logs_registrados"] = False
            resultado_envio["logs_count"] = 0
        
        # Agregar información adicional de la campaña
        resultado_envio["id_campana"] = request.id_campana
        resultado_envio["destinatarios_procesados"] = len(destinatarios)
        
        return resultado_envio
        
    except Exception as e:
        logging.error(f"Error en envioMail: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para enviar el correo")



""" @app.post("/ask/sendEmailEmployee")
async def enviar_correo_empleado(request: EnviarCorreoEmpleadoRequest):  # Usamos la clase para recibir la data
    try:
        # Normalizar destinatarios a lista
        if isinstance(request.destinatario, str):
            destinatarios = [request.destinatario.strip()] if request.destinatario.strip() else []
        else:
            destinatarios = [email.strip() for email in request.destinatario if email.strip()]
        
        # Preparar data para sendEmail
        data = {
            "destinatario": destinatarios,  # Enviar como lista
            "asunto": request.asunto,
            "cuerpo_correo": request.cuerpo_correo
        }
        
        # Llamar a la función de envío
        resultado_envio = mailing.sendEmail_marketing(data)
        
        # Si hay envíos exitosos, registrar logs
        destinatarios_exitosos = []
        if resultado_envio.get("success"):
            destinatarios_exitosos = resultado_envio.get("destinatarios_exitosos", [])
            
            # Si no viene la lista detallada, inferirla del resultado
            if not destinatarios_exitosos:
                errores_count = resultado_envio.get("errores_count", 0)
                if errores_count == 0:
                    # Todos fueron exitosos
                    destinatarios_exitosos = destinatarios
                else:
                    # Calcular exitosos basado en errores detallados
                    errores_detallados = resultado_envio.get("detalles_errores", [])
                    destinatarios_con_error = {error["destinatario"] for error in errores_detallados}
                    destinatarios_exitosos = [dest for dest in destinatarios if dest not in destinatarios_con_error]
        
        # Registrar logs solo para envíos exitosos
        if destinatarios_exitosos:
            resultado_logs = mailing.registrar_logs_envio(destinatarios_exitosos, request.id_campana)
            
            # Agregar información de logs al resultado
            resultado_envio["logs_registrados"] = resultado_logs.get("success", False)
            if resultado_logs.get("success"):
                resultado_envio["logs_count"] = resultado_logs.get("registros", 0)
            else:
                resultado_envio["logs_error"] = resultado_logs.get("message")
        else:
            resultado_envio["logs_registrados"] = False
            resultado_envio["logs_count"] = 0
        
        # Agregar información adicional de la campaña
        resultado_envio["id_campana"] = request.id_campana
        resultado_envio["destinatarios_procesados"] = len(destinatarios)
        
        return resultado_envio
        
    except Exception as e:
        logging.error(f"Error al enviar el correo al empleado: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para enviar el correo") """



#! VERSION ANTIGUA
@app.post("/ask/sendEmailEmployee2")
async def enviar_correo_empleado(request: EnviarCorreoEmpleadoRequest2):  # Usamos la clase para recibir la data
    try:
        data = {
            "user": request.user,
            "email": request.email,
            "codigo": request.codigo
        }

        # Pasar los datos al método para enviar el correo al empleado
        return mailing.sendEmailEmployee2(data)  # Llama al método real para enviar el correo

    except Exception as e:
        logging.error(f"Error al enviar el correo al empleado: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para enviar el correo")


@app.post("/ask/listProspectos", response_model=ListProspectosResponse, responses={200: {"model": ListProspectosResponse}}, tags=["Listar prospectos"])
async def list_prospectos_endpoint(datos: ListProspectosRequest):
    # Convertir los datos en diccionario para pasarlos a la función
    resultado = contactos.list_prospectos(datos.dict())
    
    # Devolver la respuesta, que ya está formateada en el formato esperado
    return resultado



@app.post("/ask/updateFoto/{idEmp}")
async def update_foto(
    idEmp: int,
    profile_picture: UploadFile = File(...),
    file_name: str = Form(...),
    file_type: str = Form(...),
):
    # Crear un diccionario con los datos del formulario
    data = {
        'profile_picture': profile_picture,
        'file_name': file_name,
        'file_type': file_type
    }
    # Pasar los datos junto con idEmp a la función updateFoto
    return my_profile.updateFoto(idEmp, data)



@app.post("/ask/obtenerCuentas")
async def obtener_cuentas(request: CuentaRequest):
    try:
        data = {
            "id_cuenta": request.id_cuenta
        }
        # Aquí debes llamar al método que obtenga las cuentas
        return account.obtenerCuentasdeServicio(data)  # Cambia esto por la lógica de negocio real
    except Exception as e:
        logging.error(f"Error al obtener cuentas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.post("/ask/insertarCuentaServicio")
async def insertar_cuenta_servicio(request: NuevoCuentaServicioRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "tipo_cuenta": request.tipo_cuenta,
            "status": request.status
        }
        # Pasar los datos al método para insertar la cuenta de servicio
        return account.insertarCuentaServicio(data)  # Llama al método real para insertar la cuenta
    except Exception as e:
        logging.error(f"Error al insertar la cuenta de servicio: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción de la cuenta de servicio")
    
@app.post("/ask/insertarContactados")
async def insertar_contacto(request: NuevoContactoRequest):  # Usamos la clase para recibir la data
    try:
        data = request.dict()
        # Pasar los datos al método para insertar la cuenta de servicio
        return contactos.insertarContacto(data)  # Llama al método real para insertar la cuenta
    except Exception as e:
        logging.error(f"Error al insertar la cuenta de servicio: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción de la cuenta de servicio")



@app.post("/ask/newPermissions")
async def insertar_permiso(request: NuevoPermisoRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "id_perfil": request.id_perfil,
            "id_modulo": request.id_modulo,
            "id_vista": request.id_vista,
            "id_elemento": request.id_elemento,
            "permiso": request.permiso
        }
        return profiling.insertarPermiso(data)  # Llama al método real para insertar el permiso
    except Exception as e:
        logging.error(f"Error al insertar el permiso: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción del permiso")



@app.post("/ask/updateGeneralInformation/{id}")
async def actualizar_general_information(id: int, request: ActualizarGeneralInformationRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "nombre": request.nombre,
            "tipo_doc": request.tipo_doc,
            "documento": request.documento,
            "correo": request.correo,
            "telefono": request.telefono,
            "direccion": request.direccion
        }

        # Pasar los datos al método para actualizar la información
        return general_information.actualizarGenInfo(id, data)  # Llama al método real para actualizar la información

    except Exception as e:
        logging.error(f"Error al actualizar la información general: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de actualización de información general")



@app.post("/ask/insertarCuentadeServicio")
async def insertar_cuenta_de_servicio(request: CuentaServicioRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "id_cuenta": request.id_cuenta,
            "dato": request.dato,
            "valor": request.valor
        }
        # Pasar los datos al método de inserción
        return account.insertarCuentadeServicio(data)  # Llama al método real de inserción

    except Exception as e:
        logging.error(f"Error al insertar cuenta de servicio: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de insertar cuenta de servicio")



@app.post("/ask/newSupport")
async def enviar_ticket_soporte(request: SoporteDataRequest):
    try:
        data = {
            "prioridad": request.prioridad,
            "modulo": request.modulo,
            "vista": request.vista,
            "asunto": request.asunto,
            "id_empleado": request.id_empleado,
            "observacion": request.observacion
        }
        return soporte.insertarSoporte(data)
    except Exception as e:
        logging.error(f"Error al enviar el correo de PQRS: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.post("/ask/sendEmailSoporte")
async def enviar_correo_soporte(request: EnviarCorreoSoporteRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "asunto": request.asunto,
            "observacion": request.observacion,
            "nombre": request.nombre,
            "modulo_name": request.modulo_name,
            "vista_name": request.vista_name,
        }
        # Llamada a la función para enviar el correo
        return mailing_support.sendEmailSoporte(data)
    except Exception as e:
        logging.error(f"Error al enviar el correo de soporte: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para enviar el correo de soporte")



@app.post("/ask/newUser")
async def insertar_empleado(request: NuevoEmpleadoRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "nombres": request.nombres,
            "apellidos": request.apellidos,
            "tipo_doc": request.tipo_doc,
            "documento": request.documento,
            "id_area": request.id_area,
            "id_cargo": request.id_cargo,
            "correo_corporativo": request.correo_corporativo,
            "correo_alterno": request.correo_alterno,
            "telefono": request.telefono,
            "direccion": request.direccion,
            "status": request.status,
            "idperfil": request.idperfil,
        }
        # Pasar los datos al método para insertar el empleado
        return employee.insertarEmpleado(data)  # Llama al método real para insertar el empleado
    except Exception as e:
        logging.error(f"Error al insertar el empleado: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción del empleado")



@app.post("/ask/NuevoRecordatorioFidelizacion")
async def insertar_recordatorio_fidelizacion(request: adjuntoFidelizacion):  # Usamos la clase para recibir la data
    try:
        data = {
            
            "id_contacto_union": request.id_contacto_union,
            "id_agente_creador": request.id_agente_creador,
            "asunto": request.asunto,
            "descripcion": request.descripcion,
            "fecha_hora": request.fecha_hora,
            "id_agente_asignado": request.id_agente_asignado,
            "id_etapa": request.id_etapa,
        }
        # Pasar los datos al método para insertar el empleado
        return contactos.insertarRecordatorioFidelizacion(data)  # Llama al método real para insertar el empleado
    except Exception as e:
        logging.error(f"Error al insertar el recordatorio: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción del empleado")



@app.post("/ask/newProfil")
async def insertar_perfil(request: NuevoPerfilRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "perfiles": request.perfiles,
            "descripcion": request.descripcion,
            "status": request.status
        }
        # Pasar los datos al método para insertar el perfil
        return profiling.insertarPerfil(data)  # Llama al método real para insertar el perfil
    except Exception as e:
        logging.error(f"Error al insertar el perfil: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción del perfil")



@app.post("/ask/listEncuestados", response_model=ListEncuestadosResponse)
async def list_encuestados_endpoint(datos: ListEncuestadosRequest):
    # Ahora ya no pasamos 'fecha' porque no lo estamos utilizando
    resultado = encuestas.obtener_encuestados(
        page=datos.page,
        page_size=datos.pageSize
    )
    return resultado



@app.post("/ask/datosTablaSeleccionada", response_model=TablaSeleccionadaResponse, responses={200: {"model": TablaSeleccionadaResponse}}, tags=["Selección de Tablas contactabilidad"])
async def datos_tabla_seleccionada_endpoint(request: TablaSeleccionadaRequest):
    try:
        data = request.dict()
        # Convertir los datos en diccionario para pasarlos a la función
        resultado = contactabilidad.datos_tabla_seleccionada(data)
        
        # Devolver la respuesta, que ya está formateada en el formato esperado
        return resultado
    except Exception as e:
        logging.error(f"Error al obtener los datos de la tabla seleccionada: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de obtener los datos de la tabla seleccionada")



@app.post("/ask/notasContacto", response_model=CreateNotesResponse, tags=["Notas de Contacto"])
async def notas_contacto(request: CreateNotesRequest):
    try:
        data = request.dict()
        resultado = contactabilidad.createNotes(data)
        
        return resultado
    except Exception as e:
        logging.error(f"Error al crear las notas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de crear las notas de contacto")


@app.post("/ask/insertarTareaPrimerContacto", response_model=dict, responses={200: {"model": dict}}, tags=["Primer Contacto"])
async def insertar_primer_contacto_endpoint(request: PrimerContactoRequest):
    try:
        data = request.dict()
        resultado = primer_contacto.insertar_primer_contacto(data)
        return resultado
    except Exception as e:
        logging.error(f"Error al insertar primer contacto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de insertar primer contacto")
    
@app.post("/ask/enviarCorreoPrimerContacto")
async def enviar_correo_primer_contacto(request: EnviarCorreoRequest):
    try:
        return malling_primer_contacto.send_email_primer_contacto(request.dict())  # Pasamos los datos como diccionario
    except Exception as e:
        logging.error(f"Error al enviar correo primer contacto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar el envío del correo")


@app.post("/ask/enviarCorreoContacto")
async def enviar_correo_contacto(request: EnviarCorreoContactoRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "email": request.email,
            "cuerpo": request.cuerpo,
            "asunto": request.asunto
        }

        # Pasar los datos al método para enviar el correo al prospecto
        return mailing.sendEmail(data)  # Llama al método real para enviar el correo

    except Exception as e:
        logging.error(f"Error al enviar el correo al ciudadano prospecto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para enviar el correo")



@app.post("/ask/sendEmailContact")
async def sendEmailContact(request: EnvioMailContactRequest):
    try:
        data = {
            "destinatario": request.destinatario,  
            "asunto": request.asunto,
            "cuerpo_correo": request.cuerpo_correo
        }
        result = mailing.sendEmail(data)
        return {"success": True, "message": "Correo enviado exitosamente", "data": result}
        
    except Exception as e:
        logging.error(f"Error al enviar el correo al empleado: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para enviar el correo")


@app.post("/ask/newArea")
async def insertar_area(request: NuevoAreaRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "area": request.area,
            "descripcion": request.descripcion
        }

        # Pasar los datos al método para insertar el área
        return my_profile.insertarArea(data)  # Llama al método real para insertar el área

    except Exception as e:
        logging.error(f"Error al insertar el área: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción del área")




@app.post("/ask/newCargos")
async def insertar_cargo(request: NuevoCargoRequest):
    try:
        data = {
            "cargo": request.cargo,
            "descripcion": request.descripcion,
            "idArea": request.idArea
        }

        # Pasar los datos al método para insertar el área
        return my_profile.insertarCargo(data)


    except Exception as e:
        logging.error(f"Error al insertar el área: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción del área")



@app.post("/ask/verificacionContactado", response_model=dict, responses={200: {"model": dict}}, tags=["verificación Contactado"])
async def func(request: verificacionContactadoRequest):
    try:
        data = request.dict()
        resultado = contactabilidad.verificacion_persona_contactada(data)
        return resultado
    except Exception as e:
        logging.error(f"Error al verficiar el contacto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de verificación de contacto")



@app.post("/ask/agregarNuevoProspecto", response_model=dict, responses={200: {"model": dict}}, tags=["Agregar nuevo contacto prospecto"])
async def func(request: agregarNuevoProspectoRequest):
    try:
        data = request.dict()
        resultado = contactabilidad.agregar_prospecto_nuevo(data)
        return resultado
    except Exception as e:
        logging.error(f"Error al agregar un nuevo contacto prospecto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de agregar un nuevo contacto prospecto")


@app.post("/ask/obtener-recordatorios")
async def obtener_recordatorios_fidelizacion(request: ObtenerRecordatoriosRequest):
    try:
        return contactos.obtener_recordatorios_por_contacto(request.id_contacto_union)
    except Exception as e:
        logging.error(f"Error al obtener recordatorios: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de obtener recordatorios")




""" ======================= APIs Archivos de propuestas ciudadano ======================= """

@app.post("/ask/obtenerUrlFirmada", response_model=ObtenerUrlFirmadaResponse, responses={400: {"model": ObtenerUrlFirmadaError}, 500: {"model": ObtenerUrlFirmadaError}}, tags=["URLs Firmadas"])
async def obtener_url_firmada_endpoint(request: ObtenerUrlFirmadaRequest):
    """
    Obtiene una URL firmada para un archivo específico en S3.
    
    Args:
        request: Contiene el s3_key del archivo
    
    Returns:
        URL firmada con tiempo de expiración
    """
    try:
        resultado = await admin_propuestas.obtener_url_firmada(request.s3_key)
        
        if not resultado["success"]:
            raise HTTPException(status_code=400, detail=resultado["message"])
        
        return ObtenerUrlFirmadaResponse(
            success=True,
            url_firmada=resultado["data"]["signed_url"]
        )
        
    except HTTPException:
        raise  # Re-lanza HTTPExceptions tal cual
    except Exception as e:
        logging.error(f"Error al obtener URL firmada: {str(e)}")
        raise HTTPException(status_code=500, detail="Error interno al generar URL firmada")


@app.post("/ask/obtenerPropuestasCrm", response_model=ObtenerPropuestasCrmResponse, responses={400: {"model": ObtenerPropuestasCrmError}, 500: {"model": ObtenerPropuestasCrmError}}, tags=["Propuestas CRM"])
async def obtener_propuestas_crm_endpoint(request: ObtenerPropuestasCrmRequest):
    """
    Obtiene las propuestas con sus archivos adjuntos de S3, paginadas.
    
    Args:
        request: Contiene page y pageSize para la paginación
    
    Returns:
        Lista paginada de propuestas con sus archivos adjuntos
    """
    try:
        resultado = await admin_propuestas.obtener_propuestas_con_archivos(request.page, request.pageSize)
        
        if not resultado["success"]:
            raise HTTPException(status_code=400, detail=resultado["message"])
        
        return ObtenerPropuestasCrmResponse(
            success=True,
            message=resultado["message"],
            data=resultado["data"],
            totalRecords=resultado["totalRecords"],
            totalPages=resultado["totalPages"],
            currentPage=resultado["currentPage"]
        )
        
    except HTTPException:
        raise  # Re-lanza HTTPExceptions tal cual
    except Exception as e:
        logging.error(f"Error al obtener propuestas CRM: {str(e)}")
        raise HTTPException(status_code=500, detail="Error interno al obtener propuestas")




# Paso 1 - Validación de formato
@app.post(
    "/ask/procesamientoExcel/prospectos/paso1/validacionFormato",
    response_model=ProcesamientoResponse,
    responses={400: {"model": ProcesamientoError}, 500: {"model": ProcesamientoError}},
    tags=["Procesamiento Excel - Prospectos"],
)
async def endpoint_paso_1(excel: UploadFile = File(...)):
    try:
        resultado = await contactabilidad.procesamiento_principal_paso_1_validacion_formato(excel)
        if not resultado.get("success", False):
            raise HTTPException(status_code=400, detail=resultado.get("message", "Error en validación de formato"))
        return ProcesamientoResponse(success=True, message=resultado.get("message", ""), data=resultado.get("id"))
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error en paso 1: {e}")
        raise HTTPException(status_code=500, detail="Error interno")


# Paso 2 - Obtener columnas desde el Excel
@app.post(
    "/ask/procesamientoExcel/prospectos/paso2/obtenerColumnasExcel",
    response_model=ProcesamientoResponse,
    responses={400: {"model": ProcesamientoError}, 500: {"model": ProcesamientoError}},
    tags=["Procesamiento Excel - Prospectos"],
)
async def endpoint_paso_2(excel: str = Body(..., embed=True)):
    try:
        resultado = await contactabilidad.procesamiento_principal_paso_2_obtener_columnas_excel(excel)
        if not resultado.get("success", False):
            raise HTTPException(status_code=400, detail=resultado.get("message", "Error al obtener columnas"))
        return ProcesamientoResponse(success=True, message=resultado.get("message", ""), data=resultado.get("data"))
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error en paso 2: {e}")
        raise HTTPException(status_code=500, detail="Error interno")



@app.post(
    "/ask/procesamientoExcel/prospectos/paso5/validacionOpenAI",
    response_model=ProcesamientoResponse,
    responses={400: {"model": ProcesamientoError}, 500: {"model": ProcesamientoError}},
    tags=["Procesamiento Excel - Prospectos"],
)
async def endpoint_paso_5(excel: str = Body(..., embed=True)):
    try:
        resultado = await contactabilidad.procesamiento_principal_paso_5_validacion_openai(excel)
        if not resultado.get("success", False):
            return ProcesamientoResponse(
                success=False,
                message="El excel no pasó la validación correspondiente",
                data={}
            )
        return ProcesamientoResponse(
            success=True,
            message=resultado.get("message", ""),
            data=resultado.get("data")
        )
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error en paso 5: {e}")
        raise HTTPException(status_code=500, detail="Error interno")




@app.post(
    "/ask/procesamientoExcel/prospectos/paso6/procesarExcel",
    response_model=ProcesamientoResponse,
    responses={400: {"model": ProcesamientoError}, 500: {"model": ProcesamientoError}},
    tags=["Procesamiento Excel - Prospectos"],
)
async def endpoint_paso_6(
    excel: str = Body(..., embed=True),  # ahora viene en el JSON
    mapeo_columnas: str = Form(...),     # se mantiene como Form
):
    try:
        # parsear JSON string a dict real
        try:
            mapeo_dict: Dict[str, str] = json.loads(mapeo_columnas)
        except json.JSONDecodeError:
            raise HTTPException(status_code=400, detail="mapeo_columnas no es un JSON válido")

        resultado = await contactabilidad.procesamiento_principal_paso_6_procesar_excel_y_guardar_en_base_de_datos(
            excel, mapeo_dict
        )

        if not resultado.get("success", False):
            raise HTTPException(
                status_code=400,
                detail=resultado.get("message", "Error al procesar Excel")
            )

        return ProcesamientoResponse(
            success=True,
            message=resultado.get("message", ""),
            data=resultado.get("data"),
        )

    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Error en paso 6: {e}")
        raise HTTPException(status_code=500, detail="Error interno")



@app.post("/ask/marketing_datosTablaSeleccionada", response_model=TablaSeleccionadaResponse, responses={200: {"model": TablaSeleccionadaResponse}}, tags=["Selección de Tablas contactabilidad"])
async def datos_tabla_seleccionada_marketing(request: TablaSeleccionadaMarketingRequest):
    try:
        data = request.dict()
        # Convertir los datos en diccionario para pasarlos a la función
        resultado = marketing.datos_tabla_seleccionada(data)
        
        # Devolver la respuesta, que ya está formateada en el formato esperado
        return resultado
    except Exception as e:
        logging.error(f"Error al obtener los datos de la tabla seleccionada: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de obtener los datos de la tabla seleccionada")



@app.post("/ask/busquedaDinamicaCampos", response_model=TablaSeleccionadaResponse, responses={200: {"model": TablaSeleccionadaResponse}}, tags=["Selección de Tablas Marketing"])
async def datos_tabla_seleccionada_endpoint(request: BusquedaPorCamposDinamicosRequest):
    try:
        data = request.dict()
        # Convertir los datos en diccionario para pasarlos a la función
        resultado = marketing.filtrado_dinamico_busqueda_campos(data)
        
        # Devolver la respuesta, que ya está formateada en el formato esperado
        return resultado
    except Exception as e:
        logging.error(f"Error al obtener los datos de la tabla filtrada: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de obtener los datos de la tabla filtrada")



@app.post("/ask/insertarEncuesta")
async def insertar_encuesta(request: NuevaEncuestaRequest):
    try:
        data = request.dict()
        # Pasar los datos al método de inserción
        return encuestas.insertar_encuesta(data)  # Llama al método real de inserción

    except Exception as e:
        logging.error(f"Error al insertar encuesta: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de insertar encuesta")



@app.post("/ask/insertarPregunta")
async def insertar_pregunta_encuesta(request: NuevaPreguntaRequest):
    try:
        data = request.dict()
        # Pasar los datos al método de inserción
        return encuestas.insertar_pregunta(data)  # Llama al método real de inserción

    except Exception as e:
        logging.error(f"Error al insertar pregunta en encuesta: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de insertar pregunta en encuesta")



@app.post("/ask/insertarRespuesta")
async def insertar_respuesta_pregunta(request: NuevaRespuestaRequest):
    try:
        data = request.dict()
        # Pasar los datos al método de inserción
        return encuestas.insertar_respuesta(data)  # Llama al método real de inserción

    except Exception as e:
        logging.error(f"Error al insertar respuesta en encuesta: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de insertar respuesta en encuesta")



@app.post("/ask/assistants")
async def get_assistants(request: AssistantsEmpresaRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "id_empresa": request.id_empresa
        }
        # Pasar los datos al método de obtener asistentes
        return login.asistentess(data)  # Llama al método real de login para obtener asistentes

    except Exception as e:
        logging.error(f"Error al obtener asistentes: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de obtener asistentes")



@app.post("/ask/enviarTiempoSesionModal")
async def insertar_tiempo_sesion(request: TiempoSesionRequest):
    try:
        data = request.dict()
        # Pasar los datos al método para insertar el tiempo de sesión
        return contactos.insertarTiempoSesion(data)
    except Exception as e:
        logging.error(f"Error al insertar el tiempo de sesión: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción del tiempo de sesión")



@app.post("/ask/completeUsersData")
async def get_complete_users_data():
    return employee.list_complete_user_data()



@app.post("/ask/inserUserAssignedContactedPerson", response_model=UserAssignedContactedResponse, responses={200: {"model": UserAssignedContactedResponse}}, tags=["Asignaciones de Usuarios a Contactados"])
async def insert_user_contact_assignment(request: UserAssignedContactedRequest):
    try:
        data = request.dict()
        # La función manejará la fecha automáticamente
        resultado = contactos.insert_user_assigned_contacted_person(data)
        
        return resultado
    except Exception as e:
        logging.error(f"Error al insertar asignación de contacto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de inserción de asignación de contacto")



@app.post("/ask/getEmailTemplate", response_model=GetEmailTemplateResponse, responses={200: {"model": GetEmailTemplateResponse}}, tags=["Obtención de Plantillas de Email"])
async def get_email_template(template_category: str = Body(..., embed=True)):
    try:
        resultado = mailing.get_email_template_by_category(template_category)
        
        return resultado
    except Exception as e:
        logging.error(f"Error al obtener la plantilla de email: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de obtención de plantilla de email")









""" ======================= Peticiones PUT ======================= """
@app.put("/ask/updatemyprofil/{id}")
async def actualizar_my_perfil(id: int, request: ActualizarPerfilRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "nombres": request.nombres,
            "apellidos": request.apellidos,
            "tipo_doc": request.tipo_doc,
            "documento": request.documento,
            "correo_corporativo": request.correo_corporativo,
            "correo_alterno": request.correo_alterno,
            "telefono": request.telefono,
            "direccion": request.direccion,
            "id_area": request.id_area,
            "id_cargo": request.id_cargo,
            "status": request.status
        }

        # Pasar los datos al método para actualizar el perfil
        return my_profile.actualizarMyPerfil(id, data)

    except Exception as e:
        logging.error(f"Error al actualizar el perfil: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para actualizar el perfil")


@app.put("/ask/updateNews/{id}")
async def actualizar_mi_noticia(
    id: int,
    principal: int = Form(...),
    fecha_noticia: str = Form(...),
    titulo: str = Form(...),
    texto_corto: str = Form(...),
    texto_largo: str = Form(...),
    id_estado: int = Form(...),
    link: str = Form(...),
    adjunto: Optional[UploadFile] = File(None)
):
    try:
        # Definir los datos que se van a actualizar
        data = {
            "principal": principal,
            "fecha_noticia": fecha_noticia,
            "titulo": titulo,
            "texto_corto": texto_corto,
            "texto_largo": texto_largo,
            "id_estado": id_estado,
            "link": link,
            "adjunto": adjunto  # El archivo ya viene como UploadFile o None
        }
        
        # Llamar al método para actualizar la noticia en la base de datos
        return noticias.actualizar_noticia(id, data)

    except Exception as e:
        logging.error(f"Error al actualizar la noticia: {e}")
        raise HTTPException(status_code=500, detail=f"Error al procesar la solicitud: {str(e)}")

@app.put("/ask/changepassword/{idUser}")
async def actualizar_contraseña(idUser: int, request: ActualizarContraseñaRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "newPassword": request.newPassword
        }

        # Pasar los datos al método para actualizar la contraseña
        return my_profile.actualizarContraseña(idUser, data)

    except Exception as e:
        logging.error(f"Error al actualizar la contraseña: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para actualizar la contraseña")



@app.put("/ask/actualizarPermiso/{id}")
async def actualizar_permiso(id: int, request: ActualizarPermisoRequest):
    try:
        data = {
            "id_perfil": request.id_perfil,
            "id_modulo": request.id_modulo,
            "id_vista": request.id_vista,
            "id_elemento": request.id_elemento,
            "permiso": request.permiso
        }

        return profiling.actualizarPermiso(id, data)

    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.put("/ask/updateEmployee/{id}")
async def actualizar_empleado(id: int, request: ActualizarEmpleadoRequest):
    try:
        data = {
            "nombres": request.nombres,
            "apellidos": request.apellidos,
            "tipo_doc": request.tipo_doc,
            "documento": request.documento,
            "correo_corporativo": request.correo_corporativo,
            "correo_alterno": request.correo_alterno,
            "telefono": request.telefono,
            "direccion": request.direccion,
            "id_area": request.id_area,
            "id_cargo": request.id_cargo,
            "idperfil": request.idperfil,
            "status": request.status,
            "nomstatus": request.nomstatus
        }
        return employee.actualizarEmpleado(id, data)
    except Exception as e:
        logging.error(f"Error al actualizar el perfil: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.put("/ask/actualizarCuentaServicio")
async def actualizar_cuenta_servicio(request: actualizarCuentaServicioRequest):
    try:
        data = {
            "id": request.id,
            "tipo_cuenta": request.tipo_cuenta,
            "status": request.status
        }
        return account.actualizarCuentaServicio(data)
    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.put("/ask/actualizarCuentadeServicio")
async def actualizar_cuenta_de_servicio(request: actualizarCuentadeServicioRequest):
    try:
        data = {
            "id": request.id,
            "dato": request.dato,
            "valor": request.valor
        }
        return account.actualizarCuentadeServicio(data)
    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.put("/ask/actualizarMesaAyuda")
async def actualizar_mesa_ayuda(request: ActualizarMesaAyudaRequest):  # Usamos la clase para recibir la data
    try:
        data = {
            "id_reporte": request.id_reporte,
            "respuesta": request.respuesta,
            "id_empleado": request.id_empleado,
            "status": request.status,
            "fecha_respuesta": request.fecha_respuesta
        }
        # Pasar los datos al método para actualizar la mesa de ayuda
        return help_desk.actualizarMesaAyuda(data)
    except Exception as e:
        logging.error(f"Error al actualizar la mesa de ayuda: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para actualizar la mesa de ayuda")



@app.put("/ask/updateProfil/{id}")
async def actualizar_perfil(id: int, request: ActualizarEmpleadoPerfilRequest):
    try:
        data = {
            "perfiles": request.perfiles,
            "descripcion": request.descripcion,
            "status": request.status
        }
        return profiling.actualizarPerfil(id, data)
    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.put("/ask/actualizar_voluntario/{id}")
async def actualizar_voluntario(id: int, request: VoluntarioUpdateRequest):
    try:
        # Obtener el nombre de la tabla
        nombre_tabla = request.nombre_tabla  # Asegúrate de que el modelo incluye "nombre_tabla"
        
        # Verificar si el nombre_tabla es válido
        if nombre_tabla not in [
            "inscripciones_voluntarios", 
            "union_voluntarios_antiguos", 
            "base_datos_10k", 
            "registros_crm_antiguo",
            "prospectos_manual"
        ]:
            raise HTTPException(status_code=400, detail="Tabla no válida especificada en la solicitud")

        # Mapeo de los campos por nombre_tabla
        tablas_mapping = {
            "inscripciones_voluntarios": {
                "tipo_documento": request.tipo_documento,
                "documento": request.documento,
                "nombres": request.nombres,
                "apellidos": request.apellidos,
                "correos": request.correos,
                "telefono": request.telefono,
                "pais": request.pais,
                "departamento": request.departamento,
                "ciudad": request.ciudad,
                "direccion": request.direccion,
                "genero": request.genero,
                "recomendado": request.recomendado,
                "nombre_recomendador": request.nombre_recomendador,
                "grupo_wp": request.grupo_wp,
                "grupo_wp1": request.grupo_wp1,
                "como_ayudar": request.como_ayudar,
                "pasion": request.pasion
            },
            "base_datos_10k": {
                "fecha_registro": request.fecha_registro,
                "ciudad": request.ciudad,
                "correos": request.correos,
                "departamento": request.departamento,
                "documento": request.documento,
                "telefono": request.telefono,
                "nombres_completos": request.nombres_completos,
                "intereses": request.intereses,
                "autorizacion": request.autorizacion
            },
            "registros_crm_antiguo": {
                "nombres": request.nombres,
                "apellidos": request.apellidos,
                "correos": request.correos,
                "telefono": request.telefono,
                "tipo_documento": request.tipo_documento,
                "documento": request.documento,
                "departamento": request.departamento,
                "ciudad": request.ciudad,
                "localidad": request.localidad,
                "barrio": request.barrio,
                "direccion": request.direccion,
                "fecha_cumpleanos": request.fecha_cumpleanos,
                "genero": request.genero,
                "tipo_sangre": request.tipo_sangre
            },
            "prospectos_manual": {
                "nombres": request.nombres,
                "apellidos": request.apellidos,
                "tipo_documento": request.tipo_documento,
                "documento": request.documento,
                "correos": request.correos,
                "telefono": request.telefono,
                "pais": request.pais,
                "departamento": request.departamento,
                "ciudad": request.ciudad,
                "localidad": request.localidad,
                "barrio": request.barrio,
                "direccion": request.direccion,
                "fecha_cumpleanos": request.fecha_cumpleanos,
                "genero": request.genero,
                "tipo_sangre": request.tipo_sangre,
                "recomendado": request.recomendado,
                "nombre_recomendador": request.nombre_recomendador,
                "grupo_wp": request.grupo_wp,
                "grupo_wp1": request.grupo_wp1,
                "como_ayudar": request.como_ayudar,
                "pasion": request.pasion,
                "intereses": request.intereses,
                "autorizacion": request.autorizacion
            }
        }

        # Obtener los datos de la tabla correspondiente junto con su nombreTabla
        data = tablas_mapping.get(nombre_tabla, {})
        data["nombre_tabla"] = nombre_tabla
        #data = tablas_mapping.get(nombre_tabla)

        if not data:
            raise HTTPException(status_code=400, detail="Datos no encontrados para la tabla especificada")

        # Llamar a la función de actualización en la base de datos
        return contactabilidad.actualizar_voluntario_db(id, data)

    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")


@app.put("/ask/actualizar_contacto/{id}")
async def actualizar_contacto(id: int, request: updateContacto):
    
    try:
        data = {
            "fecha_registro": request.fecha_registro,
            "tipo_documento": request.tipo_documento,
            "documento": request.documento,
            "nombres": request.nombres,
            "apellidos": request.apellidos,
            "correos": request.correos,
            "telefono": request.telefono,
            "pais": request.pais,
            "departamento": request.departamento,
            "ciudad": request.ciudad,
            "direccion": request.direccion,
            "genero": request.genero,
            "recomendado": request.recomendado,
            "nombre_recomendador": request.nombre_recomendador,
            "grupo_wp": request.grupo_wp,
            "grupo_wp1": request.grupo_wp1,
            "pasion": request.pasion,
            "estado_etapa": request.estado_etapa,
            "localidad": request.localidad,
            "barrio": request.barrio,
            "fecha_cumpleanos": request.fecha_cumpleanos,
            "tipo_sangre": request.tipo_sangre,
            "autorizacion": request.autorizacion,
            "origen_datos": request.origen_datos,
            "como_ayudar": request.como_ayudar,
            "nombre_embajador": request.nombre_embajador,
            "tiempo_primer_contacto": request.tiempo_primer_contacto,
            "intereses": request.intereses,
            "fecha_registro_contacto": request.fecha_registro_contacto,
        }
        resultado = contactos.actualizar_contacto(id, data)
        if not resultado.get("success"):
            raise HTTPException(status_code=500, detail=resultado.get("message", "Error al actualizar el contacto"))
        
        return resultado

    except HTTPException as e:
        raise e
    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail=str(e))



@app.put("/ask/updateArea/{id}")
async def actualizar_area(id: int, request: ActualizarAreaRequest):
    try:
        data = {
            "area": request.area,
            "descripcion": request.descripcion
        }

        return my_profile.actualizarArea(id, data)

    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.put("/ask/updateCargos/{id}")
async def actualizar_cargos(id: int, request: ActualizarCargoRequest):
    try:
        data = {
            "cargo": request.cargo,
            "descripcion": request.descripcion,
            "idArea": request.idArea
        }

        return my_profile.actualizarCargo(id, data)


    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.put("/ask/actualizarEstadoEtapa", response_model=dict, responses={200: {"model": dict}}, tags=["Actualizar Estado Etapa"])
async def func(request: actualizarEstadoEtapaRequest):
    try:
        data = request.dict()
        resultado = contactabilidad.actualizar_estado_etapa_verificado(data)
        return resultado
    except Exception as e:
        logging.error(f"Error al actualizar el estado etapa del contacto: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de actualización del estado etapa del contacto")




@app.put("/ask/updatenews/{id}")
async def actualizar_mi_noticia(
    id: int,
    principal: int = Form(...),
    fecha_noticia: str = Form(...),
    titulo: str = Form(...),
    texto_corto: str = Form(...),
    texto_largo: str = Form(...),
    id_estado: int = Form(...),
    link: str = Form(...),
    adjunto: Optional[UploadFile] = File(None)
):
    try:
        # Definir los datos que se van a actualizar
        data = {
            "principal": principal,
            "fecha_noticia": fecha_noticia,
            "titulo": titulo,
            "texto_corto": texto_corto,
            "texto_largo": texto_largo,
            "id_estado": id_estado,
            "link": link,
            "adjunto": adjunto  # El archivo ya viene como UploadFile o None
        }
        
        # Llamar al método para actualizar la noticia en la base de datos
        return noticias.actualizar_noticia(id, data)

    except Exception as e:
        logging.error(f"Error al actualizar la noticia: {e}")
        raise HTTPException(status_code=500, detail=f"Error al procesar la solicitud: {str(e)}")



@app.put("/ask/actualizar_estado_etapa/{id}")
async def actualizar_estado_etapa(id: int, request: ActualizarEstadoEtapa):
    try:
        resultado = contactos.actualizar_estado_etapa_contacto(id, request.estado_etapa, request.id_usuario)
        
        if not resultado.get("success"):
            raise HTTPException(
                status_code=500, 
                detail=resultado.get("message", "Error al actualizar el estado")
            )
        
        return resultado
    
    except HTTPException as e:
        raise e
    except Exception as e:
        logging.error(f"Error en endpoint actualizar_estado_etapa: {e}")
        raise HTTPException(status_code=500, detail=str(e))



@app.put("/ask/updateAssistant/{id}")
async def actualizar_permiso(id: int, request: ActualizarDatosAsistente):
    try:
        data = {
            "idempresa": request.idempresa,
            "nombre": request.nombre,
            "descripcion": request.descripcion,
            "imgurl": request.imgurl,
            "id" : request.id,
            "empresa": request.empresa,
        }

        return api_ia.updateAssistant(id, data)

    except Exception as e:
        logging.error(f"Error al actualizar: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud")



@app.put("/ask/actualizarEncuesta/{id_enc}")
async def actualizar_encuesta(id_enc: int, request: ActualizarEncuestaRequest):
    try:
        data = request.dict()
        # Pasar los datos al método de actualización
        return encuestas.actualizar_encuestas(id_enc, data)

    except Exception as e:
        logging.error(f"Error al actualizar encuesta: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de actualizar encuesta")

@app.put("/ask/actualizarPregunta/{id_enc_det}")
async def actualizar_pregunta_encuesta(id_enc_det: int, request: ActualizarPreguntaRequest):
    try:
        data = request.dict()
        # Pasar los datos al método de actualización
        return encuestas.actualizar_pregunta(id_enc_det, data)

    except Exception as e:
        logging.error(f"Error al actualizar pregunta en encuesta: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de actualizar pregunta en encuesta")

@app.put("/ask/actualizarRespuesta/{id_enc_res_preg}")
async def actualizar_respuesta_pregunta(id_enc_res_preg: int, request: ActualizarRespuestaRequest):
    try:
        data = request.dict()
        # Pasar los datos al método de actualización
        return encuestas.actualizar_respuesta(id_enc_res_preg, data)

    except Exception as e:
        logging.error(f"Error al actualizar respuesta en encuesta: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de actualizar respuesta en encuesta")

@app.put("/ask/desactivarEncuestasVencidas")
async def desactivar_encuestas_vencidas():
    """
    Endpoint para desactivar automáticamente todas las encuestas que han vencido
    """
    try:
        return encuestas.desactivar_encuestas_vencidas()
    except Exception as e:
        logging.error(f"Error al desactivar encuestas vencidas: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de desactivar encuestas vencidas")

@app.get("/ask/verificarEncuestaVencida/{id_enc}")
async def verificar_encuesta_vencida(id_enc: int):
    """
    Endpoint para verificar si una encuesta específica ha vencido y desactivarla si es necesario
    """
    try:
        return encuestas.verificar_y_desactivar_encuesta_especifica(id_enc)
    except Exception as e:
        logging.error(f"Error al verificar encuesta vencida: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de verificar encuesta vencida")




@app.put("/ask/updateparam/{id}")
async def update_param(id: int, request: ParamsUpdateData):
    try:
        data = request.dict()

        return api_ia.updateParams(id, data)

    except Exception as e:
        logging.error(f"Error al actualizar los parámetros: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud para actualizar los parámetros")



@app.put("/ask/updateEmailTemplate/{template_id}")
async def actualizar_plantilla_correo(template_id: int, request: ActualizarPlantillaCorreoRequest):
    try:
        return mailing.update_email_template_by_id(
            template_id=template_id,
            template_category=request.template_category,
            email_subject=request.email_subject,
            email_body=request.email_body
        )
        
    except Exception as e:
        logging.error(f"Error al actualizar plantilla de correo: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de actualización de plantilla de correo")


""" ======================= Peticiones DELETE ======================= """
@app.delete("/ask/deletePermissions/{id}")
async def eliminar_permiso(id: int):
    return profiling.eliminarPermiso(id)

@app.delete("/ask/eliminarNoticiasCrm/{id}")
async def eliminar_noticia(id: int):
    return noticias.eliminarNoticia(id)

@app.delete("/ask/deleteProfil/{id}")
async def eliminar_perfil(id: int):
    return profiling.eliminarPerfil(id)

@app.delete("/ask/eliminarPregunta/{id_enc_det}")
async def eliminar_pregunta_encuesta(id_enc_det: int):
    try:
        # Llamar a la función de eliminación de pregunta
        return encuestas.eliminar_pregunta(id_enc_det)
    except Exception as e:
        logging.error(f"Error al eliminar pregunta de encuesta: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de eliminar pregunta")
    
@app.delete("/ask/eliminarRespuesta/{id_enc_res_preg}")
async def eliminar_respuesta_pregunta(id_enc_res_preg: int):
    try:
        # Llamar a la función de eliminación de respuesta
        return encuestas.eliminar_respuesta(id_enc_res_preg)
    except Exception as e:
        logging.error(f"Error al eliminar respuesta de encuesta: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de eliminar respuesta")

@app.delete("/ask/deletearea/{id}")
async def eliminar_area(id: int):
    return my_profile.eliminarArea(id)



@app.delete("/ask/deleteCargos/{id}")
async def eliminar_cargos(id: int):
    return my_profile.eliminarCargos(id)



@app.delete("/ask/deleteForeverContact/{id}")
async def delete_contact(id: int):
    try:
        return contactos.delete_contact(id)
    except Exception as e:
        logging.error(f"Error al eliminar el contacto permanentemente: {e}")
        raise HTTPException(status_code=500, detail="Error al procesar la solicitud de eliminación permanente del contacto")


if __name__ == "__main__":
    import uvicorn
    

    uvicorn.run(app, host="0.0.0.0", port=5000)