"""
Authentication decorators for protecting routes.
"""

from functools import wraps

from flask import g, jsonify, redirect, request, session, url_for
from loguru import logger

from ...database.encrypted_db import db_manager
from ...security.url_validator import URLValidator


def _safe_redirect_to_login():
    """
    Redirect to login with validated next parameter.

    Uses request.url as next parameter only if it passes
    security validation to prevent open redirect vulnerabilities.

    Returns:
        Flask redirect response
    """
    next_url = request.url
    # Validate that next URL is safe before using it
    if URLValidator.is_safe_redirect_url(next_url, request.host_url):
        return redirect(url_for("auth.login", next=next_url))
    # Fall back to login without next parameter if validation fails
    return redirect(url_for("auth.login"))


def login_required(f):
    """
    Decorator to require authentication for a route.
    Redirects to login page if not authenticated.
    """

    @wraps(f)
    def decorated_function(*args, **kwargs):
        if "username" not in session:
            logger.debug(
                f"Unauthenticated access attempt to {request.endpoint}"
            )
            # For API routes, return JSON error instead of redirect
            if request.path.startswith("/api/") or request.path.startswith(
                "/settings/api/"
            ):
                return jsonify({"error": "Authentication required"}), 401
            return _safe_redirect_to_login()

        # Check if we have an active database connection
        username = session["username"]
        if not db_manager.is_user_connected(username):
            # Use debug level to reduce log noise for persistent sessions
            logger.debug(
                f"No database connection for authenticated user {username}"
            )
            # For API routes, return JSON error instead of redirect
            if request.path.startswith("/api/") or request.path.startswith(
                "/settings/api/"
            ):
                return jsonify({"error": "Database connection required"}), 401
            session.clear()
            return _safe_redirect_to_login()

        return f(*args, **kwargs)

    return decorated_function


def current_user():
    """
    Get the current authenticated user's username.
    Returns None if not authenticated.
    """
    return session.get("username")


def get_current_db_session():
    """
    Get the database session for the current user.
    Must be called within a login_required route.
    """
    username = current_user()
    if username:
        return db_manager.get_session(username)
    return None


def inject_current_user():
    """
    Flask before_request handler to inject current user into g.
    """
    g.current_user = current_user()
    if g.current_user:
        # Check connectivity
        if not db_manager.is_user_connected(g.current_user):
            # For API/auth routes, allow the request to continue
            if (
                request.path.startswith("/api/")
                or request.path.startswith("/auth/")
                or request.path.startswith("/settings/api/")
            ):
                logger.debug(
                    f"No database for user {g.current_user} on API/auth route"
                )
            else:
                logger.debug(
                    f"Clearing stale session for user {g.current_user}"
                )
                session.clear()
                g.current_user = None
            g.db_session = None
        else:
            # User is connected but session wasn't set by earlier middleware
            try:
                g.db_session = db_manager.get_session(g.current_user)
            except Exception:
                logger.exception(
                    f"Error getting session for user {g.current_user}"
                )
                g.db_session = None
    else:
        g.db_session = None
