"""
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


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 redirect(url_for("auth.login", next=request.url))

        # Check if we have an active database connection
        username = session["username"]
        if not db_manager.connections.get(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 redirect(url_for("auth.login", next=request.url))

        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:
        # Try to get the database session
        try:
            g.db_session = db_manager.get_session(g.current_user)
            if g.db_session is None:
                # Check if we have an active database connection for this user
                if not db_manager.connections.get(g.current_user):
                    # For authenticated users without a database connection,
                    # we need to handle this differently based on the route type

                    # For API routes and auth routes, allow the request to continue
                    # The individual route handlers will deal with the missing database
                    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:
                        # For regular routes, this is a stale session that needs clearing
                        logger.debug(
                            f"Clearing stale session for user {g.current_user}"
                        )
                        session.clear()
                        g.current_user = None
                        g.db_session = None
        except Exception as e:
            logger.exception(
                f"Error getting session for user {g.current_user}: {e}"
            )
            g.db_session = None
    else:
        g.db_session = None
