"""
Authentication routes - Login, registration, OAuth
"""
from flask import Blueprint, render_template, redirect, url_for, flash, request, session, jsonify
from flask_login import login_user, logout_user, login_required, current_user
from app import db, limiter
from app.models import User, OAuthState
from app.auth.google_oauth import google
import secrets
from datetime import datetime, timedelta

auth_bp = Blueprint('auth', __name__)


@auth_bp.route('/login')
def login():
    """Login page"""
    if current_user.is_authenticated:
        return redirect(url_for('dashboard.index'))
    return render_template('auth/login.html')


@auth_bp.route('/register')
def register():
    """Registration page"""
    if current_user.is_authenticated:
        return redirect(url_for('dashboard.index'))
    return render_template('auth/register.html')


@auth_bp.route('/logout')
@login_required
def logout():
    """Logout user"""
    session.clear()
    logout_user()
    flash('You have been logged out.', 'info')
    return redirect(url_for('main.index'))


# Google OAuth Routes

@auth_bp.route('/google/login')
@limiter.limit("10/minute")
def google_login():
    """Initiate Google OAuth login"""
    # Generate state token for security
    state = secrets.token_urlsafe(32)
    oauth_state = OAuthState(
        state=state,
        provider='google',
        expires_at=datetime.utcnow() + timedelta(hours=1),
        redirect_uri=url_for('auth.google_callback', _external=True)
    )
    db.session.add(oauth_state)
    db.session.commit()

    # Store state in session for verification
    session['oauth_state'] = state
    session['oauth_provider'] = 'google'

    # Redirect to Google
    return redirect(google.authorize_redirect(state))


@auth_bp.route('/google/callback')
def google_callback():
    """Handle Google OAuth callback"""
    # Verify state
    state = request.args.get('state')
    oauth_state = OAuthState.query.filter_by(state=state, provider='google').first()

    if not oauth_state or not oauth_state.is_valid():
        flash('Invalid OAuth state. Please try again.', 'error')
        return redirect(url_for('auth.login'))

    # Exchange code for token
    token = google.fetch_token(request.args.get('code'))

    if not token:
        flash('Failed to authenticate with Google.', 'error')
        return redirect(url_for('auth.login'))

    # Get user info
    user_info = google.get_user_info()

    if not user_info:
        flash('Failed to get user information from Google.', 'error')
        return redirect(url_for('auth.login'))

    # Find or create user
    user = User.query.filter_by(google_id=user_info['id']).first()

    if not user:
        # Check if email already exists
        user = User.query.filter_by(email=user_info['email']).first()

        if user:
            # Link Google account to existing user
            user.google_id = user_info['id']
            user.google_picture = user_info.get('picture')
            user.email_verified = True
        else:
            # Create new user
            username = user_info['email'].split('@')[0]
            counter = 1
            while User.query.filter_by(username=username).first():
                username = f"{user_info['email'].split('@')[0]}{counter}"
                counter += 1

            user = User(
                google_id=user_info['id'],
                email=user_info['email'],
                google_email=user_info['email'],
                username=username,
                full_name=user_info.get('name'),
                google_picture=user_info.get('picture'),
                email_verified=True,
                is_active=True
            )
            db.session.add(user)

        db.session.commit()

    # Clean up OAuth state
    db.session.delete(oauth_state)
    db.session.commit()

    # Login user
    login_user(user, remember=True)
    session.pop('oauth_state', None)
    session.pop('oauth_provider', None)

    flash(f'Welcome back, {user.full_name or user.username}!', 'success')

    # Redirect to next page or dashboard
    next_page = session.get('next')
    session.pop('next', None)
    return redirect(next_page or url_for('dashboard.index'))


@auth_bp.route('/google/link-instance/<int:instance_id>')
@login_required
def google_link_instance(instance_id):
    """Link Google account to specific instance"""
    from app.models import Instance

    instance = Instance.query.get_or_404(instance_id)

    # Verify ownership
    if instance.user_id != current_user.id:
        flash('You do not have permission to access this instance.', 'error')
        return redirect(url_for('dashboard.index'))

    # Generate state for instance linking
    state = secrets.token_urlsafe(32)
    oauth_state = OAuthState(
        state=state,
        provider='google',
        user_id=current_user.id,
        instance_id=instance_id,
        expires_at=datetime.utcnow() + timedelta(hours=1),
        redirect_uri=url_for('auth.google_instance_callback', _external=True)
    )
    db.session.add(oauth_state)
    db.session.commit()

    session['oauth_state'] = state
    session['oauth_instance_id'] = instance_id

    return redirect(google.authorize_redirect(state))


@auth_bp.route('/google/instance-callback')
@login_required
def google_instance_callback():
    """Handle Google OAuth callback for instance linking"""
    state = request.args.get('state')
    instance_id = session.pop('oauth_instance_id', None)

    oauth_state = OAuthState.query.filter_by(state=state, provider='google').first()

    if not oauth_state or not oauth_state.is_valid():
        flash('Invalid OAuth state. Please try again.', 'error')
        return redirect(url_for('dashboard.index'))

    # Exchange code for token
    token = google.fetch_token(request.args.get('code'))

    if not token:
        flash('Failed to authenticate with Google.', 'error')
        return redirect(url_for('dashboard.index'))

    # Get user info
    user_info = google.get_user_info()

    if user_info and instance_id:
        from app.models import Instance
        instance = Instance.query.get(instance_id)

        if instance and instance.user_id == current_user.id:
            # Store Google tokens for instance (encrypted in production)
            instance.google_access_token = token.get('access_token')
            instance.google_refresh_token = token.get('refresh_token')

            # Set expiration
            if token.get('expires_in'):
                instance.google_token_expires_at = datetime.utcnow() + timedelta(
                    seconds=token['expires_in']
                )

            instance.enable_google_calendar = True
            instance.enable_gmail = True

            db.session.delete(oauth_state)
            db.session.commit()

            flash('Google account linked successfully!', 'success')
        else:
            flash('Instance not found.', 'error')
    else:
        flash('Failed to link Google account.', 'error')

    return redirect(url_for('dashboard.manage_instance', instance_id=instance_id))


# Local authentication (optional, for admin)

@auth_bp.route('/local/login', methods=['POST'])
@limiter.limit("5/minute")
def local_login():
    """Local login for admin accounts"""
    from flask import request

    username = request.form.get('username')
    password = request.form.get('password')

    if not username or not password:
        flash('Please provide username and password.', 'error')
        return redirect(url_for('auth.login'))

    user = User.query.filter_by(username=username).first()

    if not user or not user.check_password(password):
        flash('Invalid username or password.', 'error')
        return redirect(url_for('auth.login'))

    if not user.is_active:
        flash('Your account has been disabled.', 'error')
        return redirect(url_for('auth.login'))

    login_user(user)
    flash(f'Welcome back, {user.username}!', 'success')
    return redirect(url_for('dashboard.index'))


@auth_bp.route('/check')
def check():
    """Check authentication status"""
    if current_user.is_authenticated:
        return jsonify({
            'authenticated': True,
            'user': {
                'id': current_user.id,
                'username': current_user.username,
                'email': current_user.email,
                'subscription_tier': current_user.subscription_tier
            }
        })
    return jsonify({'authenticated': False}), 401
