from flask import Blueprint, render_template, redirect, url_for, flash, request, abort
from flask_login import login_user, logout_user, login_required, current_user
from app.models import User
from app.extensions import db, limiter
from app.services.rate_limit_service import get_rate_limit, exempt_when_request_whitelisted
from app.forms import LoginForm, RegisterForm, PasswordResetRequestForm, PasswordResetForm
from werkzeug.utils import secure_filename
import os
# Reemplazo de url_parse por una alternativa más simple

# Evitar la importación circular
from app.blueprints.auth import auth_bp

# Añadir código para generar tokens de restablecimiento de contraseña
import jwt
from time import time
from flask import current_app

def get_reset_password_token(user_id, expires_in=600):
    """Genera un token JWT para restablecer contraseña"""
    return jwt.encode(
        {'reset_password': user_id, 'exp': time() + expires_in},
        current_app.config['SECRET_KEY'],
        algorithm='HS256'
    )

def verify_reset_password_token(token):
    """Verifica un token JWT para restablecer contraseña"""
    try:
        id = jwt.decode(token, current_app.config['SECRET_KEY'],
                      algorithms=['HS256'])['reset_password']
    except:
        return None
    return User.query.get(id)

@auth_bp.route('/login', methods=['GET', 'POST'])
@limiter.limit(lambda: get_rate_limit('rate.auth.login'), exempt_when=exempt_when_request_whitelisted)
def login():
    """Vista para el login de usuarios"""
    if current_user.is_authenticated:
        return redirect(url_for('public.home'))
        
    form = LoginForm()
    if form.validate_on_submit():
        # Comprobar si es un email (contiene @) o un nombre de usuario
        login_identifier = form.login.data
        
        # Buscar primero por email
        if '@' in login_identifier:
            user = User.query.filter_by(email=login_identifier).first()
        else:
            # Si no es email, buscar por nombre de usuario
            user = User.query.filter_by(username=login_identifier).first()
        
        if user is None or not user.check_password(form.password.data):
            flash('Usuario/Email o contraseña incorrectos', 'error')
            return redirect(url_for('auth_bp.login'))

        # Comprobar si el usuario está activo
        if not user.is_active:
            flash('Tu cuenta está pendiente de aprobación por un administrador.', 'warning')
            return redirect(url_for('auth_bp.login'))
            
        login_user(user, remember=form.remember_me.data)
        next_page = request.args.get('next')
        # Comprobación de seguridad simple: si 'next' contiene '://' es una URL externa
        if not next_page or '://' in next_page:
            next_page = url_for('public.home')
            
        flash('Has iniciado sesión correctamente', 'success')
        return redirect(next_page)
        
    return render_template('auth/login.html', title='Iniciar Sesión', form=form)

@auth_bp.route('/logout')
@login_required
def logout():
    logout_user()
    flash('Has cerrado sesión.', 'info')
    return redirect(url_for('public.home'))

@auth_bp.route('/register', methods=['GET', 'POST'])
@limiter.limit(lambda: get_rate_limit('rate.auth.register'), exempt_when=exempt_when_request_whitelisted)
def register():
    """Vista para registrar nuevos usuarios"""
    # Bloquear registro público si está deshabilitado por configuración
    if not current_app.config.get('ENABLE_PUBLIC_REGISTRATION', False):
        return abort(404)
    if current_user.is_authenticated:
        return redirect(url_for('public.home'))
        
    form = RegisterForm()
    if form.validate_on_submit():
        # Crear usuario pero marcarlo como inactivo hasta la aprobación
        user = User(
            username=form.username.data, 
            email=form.email.data,
            is_active=False  # El usuario no estará activo hasta que un admin lo apruebe
        )
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()

        # TODO: Implementar notificación por email a los administradores

        flash('¡Gracias por registrarte! Tu cuenta ha sido creada y está pendiente de aprobación por un administrador.', 'info')
        return redirect(url_for('public.home'))
    return render_template('auth/register.html', title='Registro', form=form)

@auth_bp.route('/reset-password-request', methods=['GET', 'POST'])
@limiter.limit(lambda: get_rate_limit('rate.auth.reset_request'), exempt_when=exempt_when_request_whitelisted)
def reset_password_request():
    """Vista para solicitar restablecimiento de contraseña"""
    if current_user.is_authenticated:
        return redirect(url_for('public.home'))
        
    form = PasswordResetRequestForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user:
            # En una implementación real enviaríamos email con el token
            token = get_reset_password_token(user.id)
            # send_password_reset_email(user, token)
            flash('Se ha enviado un correo con instrucciones para restablecer tu contraseña', 'info')
        else:
            # Por seguridad, no revelamos que el email no existe
            flash('Se ha enviado un correo con instrucciones para restablecer tu contraseña', 'info')
        return redirect(url_for('auth_bp.login'))
        
    return render_template('auth/reset_password_request.html', title='Restablecer Contraseña', form=form)

@auth_bp.route('/reset-password/<token>', methods=['GET', 'POST'])
@limiter.limit(lambda: get_rate_limit('rate.auth.reset'), exempt_when=exempt_when_request_whitelisted)
def reset_password(token):
    """Vista para establecer nueva contraseña tras reset"""
    if current_user.is_authenticated:
        return redirect(url_for('public.home'))
        
    user = verify_reset_password_token(token)
    if not user:
        flash('El enlace para restablecer la contraseña es inválido o ha expirado', 'error')
        return redirect(url_for('public.home'))
        
    form = PasswordResetForm()
    if form.validate_on_submit():
        user.set_password(form.password.data)
        db.session.commit()
        flash('Tu contraseña ha sido restablecida correctamente', 'success')
        return redirect(url_for('auth_bp.login'))
        
    return render_template('auth/reset_password.html', title='Restablecer Contraseña', form=form)


@auth_bp.route('/profile', methods=['GET', 'POST'])
@login_required
def profile():
    """Vista para el perfil de usuario"""
    if request.method == 'POST':
        # Actualizar información del perfil
        current_user.name = request.form.get('name', current_user.name)
        current_user.email = request.form.get('email', current_user.email)
        
        # Manejar subida de imagen de perfil
        if 'profile_image' in request.files:
            file = request.files['profile_image']
            if file and file.filename != '':
                # Validar tipo de archivo
                allowed_extensions = {'png', 'jpg', 'jpeg', 'gif'}
                if '.' in file.filename and file.filename.rsplit('.', 1)[1].lower() in allowed_extensions:
                    # Crear directorio si no existe
                    upload_folder = os.path.join(current_app.static_folder, 'uploads', 'profiles')
                    os.makedirs(upload_folder, exist_ok=True)
                    
                    # Generar nombre único para el archivo
                    filename = secure_filename(f"user_{current_user.id}_{file.filename}")
                    file_path = os.path.join(upload_folder, filename)
                    
                    # Eliminar imagen anterior si existe
                    if current_user.profile_image:
                        old_file = os.path.join(upload_folder, current_user.profile_image)
                        if os.path.exists(old_file):
                            os.remove(old_file)
                    
                    # Guardar nueva imagen
                    file.save(file_path)
                    current_user.profile_image = filename
                    flash('Imagen de perfil actualizada correctamente', 'success')
                else:
                    flash('Formato de imagen no válido. Use PNG, JPG, JPEG o GIF', 'error')
        
        # Cambiar contraseña si se proporciona
        if request.form.get('new_password'):
            if request.form.get('current_password'):
                if current_user.check_password(request.form.get('current_password')):
                    new_password = request.form.get('new_password')
                    if new_password:
                        current_user.set_password(new_password)
        
        # Guardar cambios en la base de datos
        try:
            db.session.commit()
            flash('Perfil actualizado correctamente', 'success')
        except Exception as e:
            db.session.rollback()
            flash('Error al actualizar el perfil', 'error')
        
        return redirect(url_for('auth_bp.profile'))
    
    return render_template('auth/profile.html', title='Mi Perfil', user=current_user)
