from flask import Blueprint, request, jsonify
from flask_jwt_extended import create_access_token, jwt_required
from app.database import db
from app.models import User, UserRole, BusinessApplicationStatus, PasswordResetToken
from app.auth import get_password_hash, verify_password, get_current_user
from app.email_service import send_password_reset_email
from datetime import datetime, timedelta, timezone
import secrets

auth_bp = Blueprint('auth', __name__)

@auth_bp.route('/register', methods=['POST'])
def register():
    """Register a new user."""
    data = request.get_json()
    
    email = data.get('email')
    password = data.get('password')
    role = data.get('role', 'customer')
    
    if not email or not password:
        return jsonify({'error': 'Email and password are required'}), 400
    
    # Check if user already exists
    existing_user = User.query.filter_by(email=email).first()
    if existing_user:
        return jsonify({'error': 'Email already registered'}), 400
    
    # Create new user
    user_id = f"user-{email.split('@')[0]}"
    new_user = User(
        id=user_id,
        email=email,
        password_hash=get_password_hash(password),
        role=UserRole(role)
    )
    
    db.session.add(new_user)
    db.session.commit()
    
    return jsonify({
        'id': new_user.id,
        'email': new_user.email,
        'role': new_user.role.value,
        'business_id': new_user.business_id,
        'business_application_status': new_user.business_application_status.value if new_user.business_application_status else None
    }), 201

@auth_bp.route('/login', methods=['POST'])
def login():
    """Login and get access token."""
    data = request.get_json()
    
    email = data.get('email')
    password = data.get('password')
    
    if not email or not password:
        return jsonify({'error': 'Email and password are required'}), 400
    
    user = User.query.filter_by(email=email).first()
    
    if not user or not verify_password(password, user.password_hash):
        return jsonify({'error': 'Incorrect email or password'}), 401
    
    access_token = create_access_token(identity=user.id)
    
    return jsonify({
        'access_token': access_token,
        'token_type': 'bearer'
    }), 200

@auth_bp.route('/me', methods=['GET'])
@jwt_required()
def get_me():
    """Get current user information."""
    user = get_current_user()
    
    if not user:
        return jsonify({'error': 'User not found'}), 404
    
    return jsonify({
        'id': user.id,
        'email': user.email,
        'role': user.role.value,
        'business_id': user.business_id,
        'business_application_status': user.business_application_status.value if user.business_application_status else None,
        'created_at': user.created_at.isoformat() if user.created_at else None
    }), 200

@auth_bp.route('/forgot-password', methods=['POST'])
def forgot_password():
    """Request password reset. Generates a reset token and sends email."""
    data = request.get_json()
    email = data.get('email')
    
    if not email:
        return jsonify({'error': 'Email is required'}), 400
    
    user = User.query.filter_by(email=email).first()
    
    # Always return success to prevent email enumeration
    if user:
        # Invalidar tokens anteriores del usuario
        PasswordResetToken.query.filter_by(usuario_id=user.id, usado=False).update({'usado': True})
        db.session.commit()
        
        # Generar nuevo token
        reset_token = secrets.token_urlsafe(32)
        expires_at = datetime.now(timezone.utc) + timedelta(hours=1)
        
        # Guardar token en base de datos
        token_record = PasswordResetToken(
            id=f"token-{secrets.token_urlsafe(16)}",
            usuario_id=user.id,
            token=reset_token,
            expira_en=expires_at,
            usado=False
        )
        db.session.add(token_record)
        db.session.commit()
        
        # Enviar email con el token
        try:
            send_password_reset_email(email, reset_token)
        except Exception as e:
            print(f"Error al enviar email: {str(e)}")
            # Continuar aunque falle el envío (el token ya está guardado)
    
    return jsonify({
        'message': 'Si el email existe, se enviará un enlace de recuperación.'
    }), 200

@auth_bp.route('/reset-password', methods=['POST'])
def reset_password():
    """Reset password with token."""
    data = request.get_json()
    email = data.get('email')
    token = data.get('token')
    new_password = data.get('new_password')
    
    if not all([email, token, new_password]):
        return jsonify({'error': 'Email, token y nueva contraseña son requeridos'}), 400
    
    if len(new_password) < 6:
        return jsonify({'error': 'La contraseña debe tener al menos 6 caracteres'}), 400
    
    user = User.query.filter_by(email=email).first()
    if not user:
        return jsonify({'error': 'Token o email inválido'}), 400
    
    # Buscar token válido
    token_record = PasswordResetToken.query.filter_by(
        usuario_id=user.id,
        token=token,
        usado=False
    ).first()
    
    if not token_record:
        return jsonify({'error': 'Token inválido o ya utilizado'}), 400
    
    # Verificar expiración
    # Asegurar que ambas fechas estén en UTC para comparar
    now_utc = datetime.now(timezone.utc)
    expires_utc = token_record.expira_en
    if expires_utc.tzinfo is None:
        # Si no tiene timezone, asumir UTC
        expires_utc = expires_utc.replace(tzinfo=timezone.utc)
    elif expires_utc.tzinfo != timezone.utc:
        # Convertir a UTC si tiene otro timezone
        expires_utc = expires_utc.astimezone(timezone.utc)
    
    if now_utc > expires_utc:
        token_record.usado = True
        db.session.commit()
        return jsonify({'error': 'El token ha expirado. Solicita uno nuevo.'}), 400
    
    # Verificar que la nueva contraseña sea diferente a la actual
    from app.auth import verify_password
    if verify_password(new_password, user.password_hash):
        return jsonify({'error': 'La nueva contraseña debe ser diferente a la actual'}), 400
    
    # Actualizar contraseña
    user.password_hash = get_password_hash(new_password)
    
    # Marcar token como usado
    token_record.usado = True
    
    db.session.commit()
    
    return jsonify({'message': 'Contraseña restablecida exitosamente'}), 200

@auth_bp.route('/verify-reset-token', methods=['POST'])
def verify_reset_token():
    """Verificar si un token de recuperación es válido."""
    data = request.get_json()
    email = data.get('email')
    token = data.get('token')
    
    if not email or not token:
        return jsonify({'error': 'Email y token son requeridos'}), 400
    
    user = User.query.filter_by(email=email).first()
    if not user:
        return jsonify({'valid': False, 'error': 'Email no encontrado'}), 200
    
    token_record = PasswordResetToken.query.filter_by(
        usuario_id=user.id,
        token=token,
        usado=False
    ).first()
    
    if not token_record:
        return jsonify({'valid': False, 'error': 'Token inválido o ya utilizado'}), 200
    
    # Verificar expiración
    now_utc = datetime.now(timezone.utc)
    expires_utc = token_record.expira_en
    if expires_utc.tzinfo is None:
        expires_utc = expires_utc.replace(tzinfo=timezone.utc)
    elif expires_utc.tzinfo != timezone.utc:
        expires_utc = expires_utc.astimezone(timezone.utc)
    
    if now_utc > expires_utc:
        return jsonify({'valid': False, 'error': 'El token ha expirado'}), 200
    
    return jsonify({'valid': True}), 200

@auth_bp.route('/request-business', methods=['POST'])
@jwt_required()
def request_business():
    """Request to register a new business."""
    user = get_current_user()
    if not user:
        return jsonify({'error': 'Authentication required'}), 401
    
    data = request.get_json()
    
    # Check if user already has a business or pending request
    if user.business_id:
        return jsonify({'error': 'Ya tienes un negocio asociado'}), 400
    
    if user.business_application_status == BusinessApplicationStatus.PENDING:
        return jsonify({'error': 'Ya tienes una solicitud pendiente'}), 400
    
    # Update user status to pending
    user.business_application_status = BusinessApplicationStatus.PENDING
    db.session.commit()
    
    return jsonify({
        'message': 'Solicitud enviada. Será revisada por un administrador.',
        'status': 'pending'
    }), 200
