from flask import request, jsonify, current_app
from app import db
from app.auth import bp
from app.models import User, Session
from datetime import datetime, timedelta
import time
import functools
import re

@bp.route('/register', methods=['POST'])
def register():
    """Register a new user"""
    data = request.get_json() or {}
    
    # Validate required fields
    required_fields = ['username', 'email', 'password']
    for field in required_fields:
        if field not in data:
            return jsonify({'error': f'Missing required field: {field}'}), 400
    
    # Validate email format
    email_regex = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(email_regex, data['email']):
        return jsonify({'error': 'Invalid email format'}), 400
    
    # Validate password strength (at least 8 characters)
    if len(data['password']) < 8:
        return jsonify({'error': 'Password must be at least 8 characters long'}), 400
    
    # Check if username already exists
    if User.query.filter_by(username=data['username']).first():
        return jsonify({'error': 'Username already exists'}), 400
    
    # Check if email already exists
    if User.query.filter_by(email=data['email']).first():
        return jsonify({'error': 'Email already exists'}), 400
    
    # Create new user
    user = User(
        username=data['username'],
        email=data['email'],
        display_name=data.get('display_name', data['username']),
        role='user'  # Default role
    )
    user.set_password(data['password'])
    
    db.session.add(user)
    db.session.commit()
    
    return jsonify({
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'display_name': user.display_name,
        'role': user.role
    }), 201

@bp.route('/login', methods=['POST'])
def login():
    """Login a user with username/email and password"""
    data = request.get_json() or {}
    
    # Validate required fields
    if 'password' not in data:
        return jsonify({'error': 'Password is required'}), 400
    
    if 'username' not in data and 'email' not in data:
        return jsonify({'error': 'Username or email is required'}), 400
    
    # Find user by username or email
    user = None
    if 'username' in data:
        user = User.query.filter_by(username=data['username']).first()
    else:
        user = User.query.filter_by(email=data['email']).first()
    
    # Check if user exists and verify password
    if not user or not user.check_password(data['password']):
        return jsonify({'error': 'Invalid credentials'}), 401
    
    # Create a session for the user
    expires_at = int((datetime.utcnow() + timedelta(days=7)).timestamp())
    session = Session(
        user_id=user.id,
        expires_at=expires_at
    )
    db.session.add(session)
    db.session.commit()
    
    # Generate JWT token
    token = user.generate_token()
    
    return jsonify({
        'token': token,
        'user': {
            'id': user.id,
            'username': user.username,
            'email': user.email,
            'display_name': user.display_name,
            'role': user.role
        }
    })

@bp.route('/logout', methods=['POST'])
def logout():
    """Log out a user by invalidating their session"""
    auth_header = request.headers.get('Authorization')
    if not auth_header or not auth_header.startswith('Bearer '):
        return jsonify({'error': 'Authorization header required'}), 401
    
    token = auth_header.split(' ')[1]
    payload = User.verify_token(token)
    if not payload:
        return jsonify({'error': 'Invalid token'}), 401
    
    # Delete all sessions for this user
    Session.query.filter_by(user_id=payload['user_id']).delete()
    db.session.commit()
    
    return jsonify({'message': 'Successfully logged out'})

def token_required(f):
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            return jsonify({'error': 'Authorization header required'}), 401
        
        token = auth_header.split(' ')[1]
        payload = User.verify_token(token)
        if not payload:
            return jsonify({'error': 'Invalid token'}), 401
        
        # Check if user has an active session
        user_id = payload['user_id']
        current_time = int(time.time())
        session = Session.query.filter_by(user_id=user_id).filter(Session.expires_at > current_time).first()
        if not session:
            return jsonify({'error': 'No active session found'}), 401
        
        # Add user to request context
        request.user_id = user_id
        request.user_role = payload['role']
        
        return f(*args, **kwargs)
    return decorated

def admin_required(f):
    @functools.wraps(f)
    @token_required
    def decorated(*args, **kwargs):
        if request.user_role != 'admin':
            return jsonify({'error': 'Admin privileges required'}), 403
        
        return f(*args, **kwargs)
    return decorated