# Archivo: UserPassword.py
# Ruta: src\App\Security\UserPassword.py
# Lenguaje: Python con Flask

from flask import current_app as app
from flask import Flask,render_template, session, jsonify, request,redirect, url_for
import os
import smtplib
import pytz
from flask_mail import Message
from Consultas_SQL.Security.UserPasswordSQL import (save_Token, consultar_profile)
import jwt
import traceback
from config import Config, Host, SCHEME
from functools import wraps
from datetime import datetime, timedelta, timezone
from flask import request, render_template, redirect, url_for, jsonify
from datetime import datetime
import bcrypt
from Consultas_SQL.conexion import get_connection
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from flask import request, render_template, redirect, url_for, jsonify
import jwt
from Consultas_SQL.Security.UserPasswordSQL import save_Token
# Importar nuestro módulo de envío de correos
import secrets


# Clave secreta para firmar tokens (en producción, usa variables de entorno)
# c
SECRET_KEY = lambda: str(app.config['SECRET_KEY'])


# Clase EmailSender integrada para uso interno
class EmailSender:
    """
    Clase para el envío de correos electrónicos sin depender de Flask-Mail.
    """
    
    def __init__(self, mail_server, mail_port, mail_use_tls, mail_username, mail_password):
        """
        Inicializa el objeto EmailSender con configuración.
        
        Args:
            mail_server: Servidor SMTP
            mail_port: Puerto SMTP
            mail_use_tls: Usar TLS para la conexión
            mail_username: Usuario para autenticación SMTP
            mail_password: Contraseña para autenticación SMTP
        """
        self.smtp_server = mail_server
        self.smtp_port = mail_port
        self.use_tls = mail_use_tls
        self.sender_email = mail_username
        self.sender_password = mail_password
        
    def send_email(self, recipients, subject, html_content=None, text_content=None):
        """
        Envía un correo electrónico.
        
        Args:
            recipients: Lista de destinatarios o un solo destinatario
            subject: Asunto del correo
            html_content: Contenido HTML del correo (opcional)
            text_content: Contenido de texto plano del correo (opcional)
            
        Returns:
            True si el correo se envió correctamente, False si hubo un error
        """
        if not html_content and not text_content:
            raise ValueError("Debe proporcionar contenido HTML o de texto para el correo")
            
        # Convertir un solo destinatario a lista
        if isinstance(recipients, str):
            recipients = [recipients]
            
        # Crear mensaje
        msg = MIMEMultipart('alternative')
        msg['Subject'] = subject
        msg['From'] = self.sender_email
        msg['To'] = ', '.join(recipients)
        
        # Agregar contenido de texto
        if text_content:
            msg.attach(MIMEText(text_content, 'plain'))
            
        # Agregar contenido HTML
        if html_content:
            msg.attach(MIMEText(html_content, 'html'))
            
        try:
            # Conectar y enviar correo
            with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
                if self.use_tls:
                    server.starttls()
                server.login(self.sender_email, self.sender_password)
                server.send_message(msg)
            return True
        except Exception as e:
            print(f"Error al enviar correo: {e}")
            print(traceback.format_exc())
            return False

def send_activation_email(app, mail, UserID_):
    """
    Genera un token JWT y envía un correo de activación al usuario.
    
    """
    try:
        UserID = int(UserID_)
        
        profile_data = consultar_profile(UserID)
        if not profile_data:
            return jsonify({'error': 'No se pudo obtener el perfil del usuario'}), 404
            
        Nombre = profile_data['Nombre']
        Email = profile_data['Email']
        
        # 1. Generar Token con tiempo de expiración explícito
        exp_time = datetime.now(timezone.utc) + timedelta(minutes=4320)###SI SE USA
        token_payload = {
            'ID': UserID,
            'username': Email,
            'Nombre': Nombre,
            'exp': exp_time.timestamp()  # Agregamos expiración explícita
        }
        recipient_email = Email
        user_id = UserID
        user_name = Nombre

        print("Tipo de SECRET_KEY:", type(SECRET_KEY()))
        print("Valor de SECRET_KEY:", SECRET_KEY())
        
        token = jwt.encode(
            token_payload, 
            SECRET_KEY(),
            algorithm="HS256"
        )
        
        if isinstance(token, bytes):
            token = token.decode('utf-8')
        

        # 2. Guardar Token y obtener su ID
        token_id = save_Token(UserID, token)
        
        # Si token_id es None, significa que el usuario no existe
        if token_id is None:
            return jsonify({
                'error': f'El usuario con ID {UserID} no existe en el sistema'
            }), 404
            
        
        # 3. Enviar correo electrónico de activación
        
        try:
            # Crear URL de activación con los parámetros necesarios
            activation_url = f"{SCHEME}://{Host}/password_confirm?token={token}&userid={user_id}&email={recipient_email}&name={user_name}"
            # Obtener el correo del empleado
            destinatario = recipient_email
            data = {
                "activation_url": activation_url,
                "user_name": user_name
            }
            
            # Asunto del correo
            asunto = "Configuración de password"
            
            # Contenido HTML del correo
            html_content = render_template('Security/UserPasswordemail.html', data=data)
            
            # Intentar usar Flask-Mail primero
            email_sent = False
            try:
                # Crear el mensaje
                msg = Message(
                    asunto,
                    sender=app.config['MAIL_USERNAME'],
                    recipients=[destinatario]
                )
                
                # Adjuntar contenido HTML al mensaje
                msg.html = html_content
                
                # Enviar correo usando Flask-Mail
                mail.send(msg)
                email_sent = True
                
            except Exception as e:
                print(f"Error al usar Flask-Mail: {e}")
                
                # Si Flask-Mail falla, usar la implementación interna de EmailSender
                try:
                    email_sender = EmailSender(
                        app.config['MAIL_SERVER'],
                        app.config['MAIL_PORT'],
                        app.config['MAIL_USE_TLS'],
                        app.config['MAIL_USERNAME'],
                        app.config['MAIL_PASSWORD']
                    )
                    
                    email_sent = email_sender.send_email(
                        destinatario, 
                        asunto, 
                        html_content=html_content
                    )
                except Exception as e2:
                    print(f"Error al usar EmailSender: {e2}")
                    print(traceback.format_exc())
                    raise
            
            if not email_sent:
                return jsonify({'error': 'No se pudo enviar el correo de activación'}), 500
                
            
            # 4. Devolver respuesta JSON
            return jsonify({
                'token': token, 
                'token_id': token_id,
                'email_sent': email_sent
            })
            
        except Exception as e:
            print(f"===== Error al enviar correo de activación: {e} =====")
            print(f"===== Traceback completo: {traceback.format_exc()} =====")
            return jsonify({'error': f'Error al enviar correo: {str(e)}'}), 500

    except Exception as e:
        # Captura cualquier excepción
        print(f"===== Error en send_activation_email: {e} =====")
        print(f"===== Tipo de excepción: {type(e)} =====")
        print(f"===== Traceback completo: {traceback.format_exc()} =====")
        return jsonify({'error': f'Error: {str(e)}'}), 500

# Función auxiliar para verificar tokens
def verify_token(token):
    """
    Verifica que un token JWT sea válido
    
    Args:
        token: Token JWT a verificar
        
    Returns:
        Datos del payload si es válido, None si no lo es
    """
    try:
        payload = jwt.decode(token, SECRET_KEY(), algorithms=["HS256"])
        return payload
    except jwt.ExpiredSignatureError:
        return None
    except jwt.InvalidTokenError:
        return None

def Token_sign(app):
    @app.route('/Tokensign/<UserID>/<Email>/<Nombre>', methods=['GET'])
    def generar_token(UserID, Email, Nombre):
        
        try:
            # Validar los parámetros recibidos
            if not UserID or not Email or not Nombre:
                print("===== Error: Campos incompletos =====")
                return jsonify({'error': 'Todos los campos son obligatorios'}), 400
                
            # 1. Generar Token con tiempo de expiración explícito
            print("===== Iniciando generación de token =====")
            exp_time = datetime.now(timezone.utc) + timedelta(minutes=4320)#### NO SE USA
            token_payload = {
                'ID': UserID,
                'username': Email,
                'Nombre': Nombre,
                'exp': exp_time
            }
            print(f"===== Token payload preparado: {token_payload} =====")
            
            # Asegurarse de que la SECRET_KEY esté configurada
            if not app.config.get('SECRET_KEY'):
                print("===== Error: SECRET_KEY no configurada =====")
                return jsonify({'error': 'Configuración del servidor incompleta'}), 500
            
            print("===== Iniciando jwt.encode =====")    
            token = jwt.encode(
                token_payload, 
                SECRET_KEY(), 
                algorithm="HS256"
            )
            
            if isinstance(token, bytes):
                token = token.decode('utf-8')
            print(f"===== Token generado (tipo: {type(token)}): {token} =====")
            # 2. Guardar Token y obtener su ID
            print("===== Guardando token en base de datos =====")
            token_id = save_Token(UserID, token)
            
            # Si token_id es None, significa que el usuario no existe
            if token_id is None:
                print(f"===== Error: El UserID {UserID} no existe en la tabla Users =====")
                return jsonify({
                    'error': f'El usuario con ID {UserID} no existe en el sistema'
                }), 404
                
            print(f"===== Token guardado con ID: {token_id} =====")
            # 3. Enviar correo electrónico de activación
            print("===== Enviando correo de activación =====")
            email_sender = EmailSender()
            email_sent = email_sender.send_activation_email(
                recipient_email=Email,
                user_name=Nombre,
                user_id=UserID,
                token=token
            )
            # 4. Devolver respuesta JSON
            print("===== Preparando respuesta JSON =====")
            return jsonify({
                'token': token, 
                'token_id': token_id,
                'email_sent': email_sent
            })

        except Exception as e:
            # Captura cualquier excepción
            print(f"===== Error en generar_token: {e} =====")
            print(f"===== Tipo de excepción: {type(e)} =====")
            import traceback
            print(f"===== Traceback completo: {traceback.format_exc()} =====")
            return jsonify({'error': f'Error: {str(e)}'}), 500
    return generar_token
        #return generar_token # Retornar la función generar_token
    
def activate_account_routes(app):
    @app.route('/activate', methods=['GET'])
    def activate_account():
        # Obtener parámetros de la URL
        token = request.args.get('token')
        user_id = request.args.get('userid')
        email = request.args.get('email')
        name = request.args.get('name')
        
        if not token or not user_id:
            return render_template('Security/UserPassword.html', 
                                  message='Enlace de activación inválido o incompleto.')
        
        try:
            # Verificar si el token existe y no ha sido usado
            check_token_query = """
                SELECT ActivationTokenID, Token, ExpiresAt, IsUsed 
                FROM ActivationTokens 
                WHERE UserID = ? AND Token = ?
            """
            
            with get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute(check_token_query, [user_id, token])
                token_data = cursor.fetchone()
                
                if not token_data:
                    return render_template('Security/UserPassword.html', 
                                          message='Token no encontrado o inválido.')
                
                token_id, db_token, expires_at, is_used = token_data
                
                # Verificar si el token ya ha sido usado
                if is_used:
                    return render_template('Security/UserPassword.html', 
                                          message='Este enlace de activación ya ha sido utilizado.')
                
                # Verificar si el token ha expirado
                if datetime.utcnow() > expires_at:
                    return render_template('Security/UserPassword.html', 
                                          message='El enlace de activación ha expirado.')
                
                # Decodificar el token para verificar que sea válido
                try:
                    decoded_token = jwt.decode(
                        token, 
                        SECRET_KEY(), 
                        algorithms=["HS256"],
                        options={"verify_exp": True}
                    )
                except jwt.ExpiredSignatureError:
                    return render_template('Security/UserPassword.html', 
                                          message='El token ha expirado.')
                except jwt.InvalidTokenError:
                    return render_template('Security/UserPassword.html', 
                                          message='Token inválido.')
                
                # Marcar el token como usado
                update_token_query = """
                    UPDATE ActivationTokens 
                    SET IsUsed = 1 
                    WHERE ActivationTokenID = ?
                """
                cursor.execute(update_token_query, [token_id])
                
                # Actualizar el usuario a activado/verificado (puedes adaptar esto según tu esquema)
                update_user_query = """
                    UPDATE Users 
                    SET Status = 'ACTIVO' 
                    WHERE UserID = ?
                """
                cursor.execute(update_user_query, [user_id])
                
                conn.commit()
                
                # Redirigir a la página de éxito o mostrar un mensaje
                return render_template('Security/UserPassword.html', exito='exito',
                                      name=name or decoded_token.get('Nombre', 'Usuario'))
                
        except Exception as e:
            print(f"Error durante la activación: {e}")
            return render_template('Security/UserPassword.html', 
                                  message='Ha ocurrido un error durante la activación.')
    
    return activate_account

def user_has_access(user_id, module_name, action='read'):
    """
    Verifica si el usuario (user_id) tiene permiso de 'read', 'create',
    'edit' o 'delete' sobre el m¨®dulo (module_name).
    
    Retorna True/False.
    """
    conn = get_connection()
    cursor = conn.cursor()

    # 1) Obtener los roles del usuario
    sql_get_roles = """
        SELECT r.RoleID, r.RoleName
        FROM Roles r
        INNER JOIN UserRoles ur ON r.RoleID = ur.RoleID
        WHERE ur.UserID = ?
    """
    cursor.execute(sql_get_roles, (user_id,))
    roles = cursor.fetchall()  
    # roles ser¨¢ una lista de filas con [RoleID, RoleName, IsSuperRole]

    if not roles:
        return False  # el usuario no tiene roles => no puede acceder

    # 2) Verificar si alguno es super rol => acceso total inmediato
    #for row in roles:
        # row: (RoleID, RoleName, IsSuperRole)
        #if row.IsSuperRole:  # asumiendo que IsSuperRole es un bit/boolean
        #    return True

    # 3) Conocer el ModuleID a partir del module_name
    sql_get_module = """
        SELECT ModuleID
        FROM Modules
        WHERE ModuleName = ?
    """
    cursor.execute(sql_get_module, (module_name,))
    mod_row = cursor.fetchone()
    if not mod_row:
        return False  # M¨®dulo no existe o no est¨¢ dado de alta
    module_id = mod_row.ModuleID

    # 4) Recorrer cada rol del usuario y verificar si alguno tiene permisos en RoleModules
    #    seg¨²n la acci¨®n solicitada
    for row in roles:
        role_id = row.RoleID
        
        sql_check_permission = """
            SELECT CanRead, CanCreate, CanEdit, CanDelete
            FROM RoleModules
            WHERE RoleID = ? AND ModuleID = ?
        """
        cursor.execute(sql_check_permission, (role_id, module_id))
        perm_row = cursor.fetchone()

        if perm_row:
            # perm_row: (CanRead, CanCreate, CanEdit, CanDelete)
            can_read, can_create, can_edit, can_delete = perm_row
            if action == 'read'   and can_read:   return True
            if action == 'create' and can_create: return True
            if action == 'edit'   and can_edit:   return True
            if action == 'delete' and can_delete: return True

    # Si ning¨²n rol del usuario tiene el permiso apropiado
    return False

def password_confirm_routes(app):
    @app.route('/password_confirm', methods=['GET'])
    def password_confirm():
        """
        Muestra la página para confirmar/establecer la contraseña.
        Verifica el token recibido por URL.
        """
        # Obtener parámetros de la URL
        token = request.args.get('token')
        user_id = request.args.get('userid')
        email = request.args.get('email')
        nombre = request.args.get('name')
        
        if not token or not user_id:
            return render_template('Security/UserPassword.html', 
                                  token_valid=False,
                                  error_message='Enlace incompleto. Faltan parámetros necesarios.')
        
        try:
            # Verificar si el token existe y no ha sido usado
            check_token_query = """
                SELECT ActivationTokenID, Token, ExpiresAt, IsUsed 
                FROM ActivationTokens 
                WHERE UserID = ? AND Token = ?
            """
            
            with get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute(check_token_query, [user_id, token])
                token_data = cursor.fetchone()
                
                if not token_data:
                    #return render_template('Security/UserPassword.html',  token_valid=False,error_message='Token no encontrado o inválido.')
                    return render_template('AccessDened.html',  token_valid=False,error_message='Token no encontrado o inválido.')
                    
                token_id, db_token, expires_at, is_used = token_data
                
                # Verificar si el token ya ha sido usado
                if is_used:
                    return render_template('Security/UserPassword.html', 
                                          token_valid=False,
                                          error_message='Este enlace ya ha sido utilizado.')
                
                # Verificar si el token ha expirado
                if datetime.utcnow() > expires_at:
                    return render_template('Security/UserPassword.html', 
                                          token_valid=False,
                                          error_message='El enlace ha expirado.')
                
                # Decodificar el token para verificar que sea válido
                try:
                    decoded_token = jwt.decode(
                        token, 
                        SECRET_KEY(), 
                        algorithms=["HS256"],
                        options={"verify_exp": True}
                    )
                    
                    # Si no se proporcionó el nombre o el email en la URL, usarlos del token
                    if not nombre:
                        nombre = decoded_token.get('Nombre', '')
                    if not email:
                        email = decoded_token.get('username', '')
                    
                except jwt.ExpiredSignatureError:
                    return render_template('Security/UserPassword.html', 
                                          token_valid=False,
                                          error_message='El token ha expirado.')
                except jwt.InvalidTokenError:
                    return render_template('Security/UserPassword.html', 
                                          token_valid=False,
                                          error_message='Token inválido.')
                
                # Token válido, mostrar formulario
                return render_template('Security/UserPassword.html',
                                      token_valid=True,
                                      token=token,
                                      user_id=user_id,
                                      email=email,
                                      nombre=nombre)
                
        except Exception as e:
            print(f"Error al verificar el token: {e}")
            return render_template('Security/UserPassword.html', 
                                  token_valid=False,
                                  error_message='Ha ocurrido un error durante la verificación del token.')
    
    @app.route('/set_password', methods=['POST'])
    def set_password():
        """
        Recibe y procesa la contraseña establecida por el usuario.
        """
        try:
            data = request.get_json()
            
            if not data:
                return jsonify({'success': False, 'message': 'No se recibieron datos.'}), 400
            
            token = data.get('token')
            user_id = data.get('userId')
            password = data.get('password')
            confirm_password = data.get('confirmPassword')
            
            if not token or not user_id or not password or not confirm_password:
                return jsonify({'success': False, 'message': 'Faltan datos requeridos.'}), 400
            
            # Verificar que las contraseñas coincidan
            if password != confirm_password:
                return jsonify({'success': False, 'message': 'Las contraseñas no coinciden.'}), 400
            
            # Verificar token en la base de datos
            check_token_query = """
                SELECT ActivationTokenID, ExpiresAt, IsUsed 
                FROM ActivationTokens 
                WHERE UserID = ? AND Token = ?
            """
            
            with get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute(check_token_query, [user_id, token])
                token_data = cursor.fetchone()
                
                if not token_data:
                    return jsonify({'success': False, 'message': 'Token no válido.'}), 400
                
                token_id, expires_at, is_used = token_data
                
                # Verificar si el token ya ha sido usado
                if is_used:
                    return jsonify({'success': False, 'message': 'Este enlace ya ha sido utilizado.'}), 400
                
                # Verificar si el token ha expirado
                if datetime.utcnow() > expires_at:
                    return jsonify({'success': False, 'message': 'El enlace ha expirado.'}), 400
                
                # Hashear la contraseña con bcrypt (algoritmo seguro para contraseñas)
                salt = bcrypt.gensalt(rounds=12)  # Rounds=12 es un buen balance entre seguridad y rendimiento
                hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')
                
                print(f"Contraseña cifrada generada: {hashed_password}")
                print(f"Longitud del hash: {len(hashed_password)} caracteres")
                
                # Verificar que el hash no exceda el tamaño del campo (NVARCHAR(500))
                if len(hashed_password) > 500:
                    return jsonify({
                        'success': False, 
                        'message': 'Error interno: El hash de la contraseña excede el tamaño permitido.'
                    }), 500
                
                # Actualizar la contraseña del usuario y cambiar status a ACTIVO
                update_user_query = """
                    UPDATE Users 
                    SET PasswordHash = ?, Status = 'ACTIVO', LastLogin = GETDATE()
                    WHERE UserID = ?
                """
                cursor.execute(update_user_query, [hashed_password, user_id])
                
                # Marcar el token como usado
                update_token_query = """
                    UPDATE ActivationTokens 
                    SET IsUsed = 1 
                    WHERE ActivationTokenID = ?
                """
                cursor.execute(update_token_query, [token_id])
                
                conn.commit()
                
                return jsonify({
                    'success': True, 
                    'message': 'Contraseña establecida correctamente. Serás redirigido al inicio de sesión.', 
                    'redirect': '/login'
                })
                
        except Exception as e:
            print(f"Error al establecer la contraseña: {e}")
            return jsonify({'success': False, 'message': f'Error al establecer la contraseña: {str(e)}'}), 500

    return password_confirm

def password_recovery_routes(app, mail=None):
    
    @app.route('/auth/forgot-password', methods=['POST'])
    def request_password_reset():
        """
        Procesa la solicitud de recuperación de contraseña.
        Genera un token y envía un correo electrónico al usuario.
        """
        try:
            data = request.get_json()
            
            if not data or not data.get('email'):
                return jsonify({'success': False, 'message': 'Correo electrónico requerido'}), 400
            
            email = data.get('email')
            
            # Verificar si el correo existe en la base de datos
            with get_connection() as conn:
                cursor = conn.cursor()
                
                # Consulta para verificar si el email existe
                check_query = """
                    SELECT UserID, Email, Status
                    FROM Users
                    WHERE Email = ?
                """
                cursor.execute(check_query, [email])
                user_data = cursor.fetchone()
                
                if not user_data:
                    # No informar al usuario si el correo no existe (por seguridad)
                    return jsonify({
                        'success': True,
                        'message': 'Si tu correo está registrado, recibirás un enlace para restablecer tu contraseña.'
                    })
                
                user_id, user_email, status = user_data
                
                # Verificar si ya existe un token para este usuario
                check_token_query = """
                    SELECT ActivationTokenID 
                    FROM ActivationTokens 
                    WHERE UserID = ? AND IsUsed = 0
                """
                cursor.execute(check_token_query, [user_id])
                existing_token = cursor.fetchone()
                
                # Consulta para obtener el nombre completo del usuario
                traer_nombre = """
                    SELECT FirstName, MiddleName, LastName, SecondLastName
                    FROM Profiles
                    WHERE UserID = ?
                """
                cursor.execute(traer_nombre, [user_id])
                user_data2 = cursor.fetchone()
                
                if user_data2:
                    # Filtra los valores None o vacíos y une los válidos con espacios
                    Nombre_Completo = " ".join([part for part in user_data2 if part and part.strip()])
                    
                    # Si después de todo no hay componentes válidos
                    if not Nombre_Completo.strip():
                        Nombre_Completo = "Usuario"
                else:
                    Nombre_Completo = "Usuario"
                
                # Generar token para recuperación de contraseña
                expiry_time = datetime.utcnow() + timedelta(hours=1)  # El token expira en 1 hora
                
                # Crear payload del token
                token_payload = {
                    'ID': user_id,
                    'username': user_email,
                    'exp': expiry_time,
                    'type': 'password_reset'  # Tipo de token para distinguirlo
                }
                
                # Generar token JWT
                jwt_token = jwt.encode(
                    token_payload, 
                    SECRET_KEY(), 
                    algorithm="HS256"
                )
                
                # Verificar si ya existe un token para este usuario
                check_token_query = """
                    SELECT ActivationTokenID 
                    FROM ActivationTokens 
                    WHERE UserID = ? AND IsUsed = 0
                """
                cursor.execute(check_token_query, [user_id])
                existing_token = cursor.fetchone()
                
                if existing_token:
                    
                    # Actualizar el token existente
                    token_id = existing_token[0]
                    update_token_query = """
                        UPDATE ActivationTokens
                        SET Token = ?, ExpiresAt = ?, CreatedAt = GETDATE(), IsUsed = 0
                        WHERE ActivationTokenID = ?
                    """
                    cursor.execute(update_token_query, [jwt_token, expiry_time, token_id])
                else:
                    insert_token_query = """
                        INSERT INTO ActivationTokens (UserID, Token, CreatedAt, ExpiresAt, IsUsed)
                        OUTPUT INSERTED.ActivationTokenID
                        VALUES (?, ?, GETDATE(), ?, 0)
                    """
                    cursor.execute(insert_token_query, [user_id, jwt_token, expiry_time])
                    row = cursor.fetchone()
                    token_id = row[0] if row else None
                
                conn.commit()
            
            # Preparar datos para el correo electrónico
            destinatario = user_email
            asunto = "Restaure su contraseña"
            activation_url = f"http://{Host}/password_confirm?token={jwt_token}&userid={user_id}&email={user_email}&name={Nombre_Completo}"
            
            data = {
                "activation_url": activation_url,
                "user_name": Nombre_Completo,
                "token": jwt_token
            }
            
            # Renderizar el cuerpo del correo utilizando la plantilla HTML
            cuerpo_html = render_template('Security/UserPasswordemail.html', data=data)
            
            # Crear el mensaje
            msg = Message(
                asunto,
                sender=app.config['MAIL_USERNAME'],
                recipients=[destinatario]
            )
            
            # Asignar el cuerpo HTML
            msg.html = cuerpo_html
            
            # Enviar el correo (sin with app.app_context() redundante)
            mail.send(msg)
                
            return jsonify({
                'success': True,
                'message': 'Se ha enviado un enlace para restablecer tu contraseña. Por favor, revisa tu correo electrónico.'
            })
                
        except Exception as e:
            print(f"Error en solicitud de restablecimiento: {e}")
            import traceback
            print(traceback.format_exc())  # Muestra el stack trace completo para debugging
            return jsonify({
                'success': False,
                'message': 'Error al procesar la solicitud. Por favor, inténtalo más tarde.'
            }), 500      
        
    @app.route('/reset-password', methods=['GET'])
    def reset_password_page():
        """
        Muestra la página para establecer una nueva contraseña.
        Verifica que el token sea válido.
        """
        token = request.args.get('token')
        user_id = request.args.get('userid')
        
        print(f"===== reset_password_page: token={token}, user_id={user_id} =====")
        
        if not token or not user_id:
            print("===== Error: Falta token o user_id en la URL =====")
            return render_template('Security/UserPassword.html', 
                                token_valid=False,
                                error_message='Enlace incompleto. Faltan parámetros necesarios.')
        
        try:
            # Verificar si el token existe y no ha sido usado
            check_token_query = """
                SELECT ActivationTokenID, Token, ExpiresAt, IsUsed 
                FROM ActivationTokens 
                WHERE UserID = ? AND Token = ?
            """
            
            with get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute(check_token_query, [user_id, token])
                token_data = cursor.fetchone()
                
                if not token_data:
                    print(f"===== Error: Token no encontrado en la base de datos para user_id={user_id} =====")
                    # Buscar todos los tokens de este usuario para debugging
                    cursor.execute("SELECT ActivationTokenID, Token, ExpiresAt, IsUsed FROM ActivationTokens WHERE UserID = ?", [user_id])
                    all_tokens = cursor.fetchall()
                    print(f"===== Tokens encontrados para user_id={user_id}: {all_tokens} =====")
                    
                    return render_template('Security/UserPassword.html', 
                                        token_valid=False,
                                        error_message='Token no encontrado o inválido.')
                
                token_id, db_token, expires_at, is_used = token_data
                print(f"===== Token encontrado: ID={token_id}, expira={expires_at}, usado={is_used} =====")
                
                # Verificar si el token ya ha sido usado
                if is_used:
                    print(f"===== Error: Token ya utilizado (ID={token_id}) =====")
                    return render_template('Security/UserPassword.html', 
                                        token_valid=False,
                                        error_message='Este enlace ya ha sido utilizado.')
                
                # Verificar si el token ha expirado
                now = datetime.utcnow()
                if now > expires_at:
                    print(f"===== Error: Token expirado (ID={token_id}). Actual: {now}, Expira: {expires_at} =====")
                    return render_template('Security/UserPassword.html', 
                                        token_valid=False,
                                        error_message='El enlace ha expirado.')
                
                # Decodificar el token para verificar que sea válido
                try:
                    decoded_token = jwt.decode(
                        token, 
                        SECRET_KEY(), 
                        algorithms=["HS256"],
                        options={"verify_exp": True}
                    )
                    
                    print(f"===== Token decodificado exitosamente: {decoded_token} =====")
                    
                    # Verificar tipo de token (que sea para restablecimiento)
                    token_type = decoded_token.get('type')
                    if token_type and token_type != 'password_reset':
                        print(f"===== Error: Tipo de token incorrecto: {token_type} =====")
                        return render_template('Security/UserPassword.html', 
                                            token_valid=False,
                                            error_message='Tipo de token inválido.')
                    
                    # Obtener email del usuario para mostrarlo en el formulario
                    email = decoded_token.get('username', '')
                    
                    # Buscar nombre del usuario
                    get_user_query = """
                        SELECT Email, Nombre FROM Users WHERE UserID = ?
                    """
                    cursor.execute(get_user_query, [user_id])
                    user_row = cursor.fetchone()
                    
                    if user_row:
                        db_email, nombre = user_row
                        # Si el email no está en el token, usar el de la base de datos
                        if not email:
                            email = db_email
                    else:
                        nombre = ''
                    
                    print(f"===== Usuario encontrado: email={email}, nombre={nombre} =====")
                    
                except jwt.ExpiredSignatureError as e:
                    print(f"===== Error: Token JWT expirado: {e} =====")
                    return render_template('Security/AccessDened.html', 
                                        token_valid=False,
                                        error_message='El token ha expirado.')
                except jwt.InvalidTokenError as e:
                    print(f"===== Error: Token JWT inválido: {e} =====")
                    return render_template('Security/AccessDened.html', 
                                        token_valid=False,
                                        error_message='Token inválido.')
                except Exception as e:
                    print(f"===== Error decodificando token: {e} =====")
                    # Si hay un error decodificando, aún podemos intentar obtener información del usuario
                    get_user_query = """
                        SELECT Email, Nombre FROM Users WHERE UserID = ?
                    """
                    cursor.execute(get_user_query, [user_id])
                    user_row = cursor.fetchone()
                    
                    if user_row:
                        email, nombre = user_row
                    else:
                        email, nombre = '', ''
                
                # Token válido, mostrar formulario para cambiar contraseña
                print("===== Token válido, mostrando formulario =====")
                return render_template('Security/UserPassword.html', 
                                    token_valid=True,
                                    token=token,
                                    user_id=user_id,
                                    email=email,
                                    nombre=nombre,
                                    is_password_reset=True)
                
        except Exception as e:
            print(f"===== Error inesperado en reset_password_page: {e} =====")
            import traceback
            print(traceback.format_exc())
            return render_template('Security/AccessDened.html', 
                                token_valid=False,
                                error_message=f'Ha ocurrido un error durante la verificación: {str(e)}')
    
    return password_recovery_routes
