"""
Authentication utilities for B-Fabric web applications.
"""

from typing import Any, Optional

from dash import html, Input, Output

from bfabric_web_apps.utils.components import no_auth, access_denied, not_elevated


def get_session_id(token_data: Optional[dict]) -> Optional[str]:
    """
    Get a unique session ID for file upload isolation.

    Returns a deterministic session ID based on user and job ID,
    ensuring uploaded files are isolated per-user per-session.
    Returns None if not authenticated.

    Args:
        token_data: The token data dictionary from process_url_and_token().
                   Expected to contain 'user_data' and 'jobId' keys.

    Returns:
        A session ID string in the format "{user_login}_{job_id}",
        or None if token_data is not provided.

    Example:
        >>> session_id = get_session_id(token_data)
        >>> # Returns: "jsmith_12345"
        >>>
        >>> session_id = get_session_id(None)
        >>> # Returns: None
    """
    if not token_data:
        return None

    user = token_data.get("user_data", "anonymous")
    job_id = token_data.get("jobId", "")
    return f"{user}_{job_id}"


def register_auth_callback(
    app,
    main_content: Any,
    landing_page: Any = None,
    access_denied_page: Any = None,
    not_elevated_page: Any = None,
    require_elevated: bool = False,
    container_id: str = "main-content-container",
    tabs_container_id: str = "tabs-container",
):
    """
    Register an auth routing callback that swaps content based on auth state.

    This callback updates the main content container based on token_data:
    - No token: shows landing_page, hides tabs
    - Token with access_denied: shows access_denied_page, hides tabs
    - Token with is_elevated=False (and require_elevated=True): shows not_elevated_page, hides tabs
    - Valid token with proper access: shows main_content, shows tabs

    Args:
        app: The Dash application instance.
        main_content: Content to show when authenticated with API access.
        landing_page: Content for unauthenticated users. Defaults to no_auth().
        access_denied_page: Content when authenticated but no API access.
                           Defaults to access_denied().
        not_elevated_page: Content when user is authenticated but not elevated.
                          Defaults to not_elevated().
        require_elevated: If True, non-elevated users see not_elevated_page.
                         If False, non-elevated users see main_content.
                         Defaults to False for backwards compatibility.
        container_id: The ID of the container div to update.
                     Defaults to "main-content-container".
        tabs_container_id: The ID of the tabs container div.
                          Defaults to "tabs-container".

    Example:
        >>> app = create_app(__name__)
        >>> app.layout = get_static_layout(
        ...     base_title="My App",
        ...     main_content=html.Div()  # placeholder
        ... )
        >>> register_auth_callback(
        ...     app,
        ...     main_content=my_actual_content,
        ...     require_elevated=True,  # Block non-elevated users
        ...     landing_page=html.Div([
        ...         html.H2("Welcome to My App"),
        ...         html.P("Please log in via B-Fabric to continue.")
        ...     ])
        ... )
    """
    # Set defaults - components now return dbc.Alert directly
    if landing_page is None:
        landing_page = no_auth()
    if access_denied_page is None:
        access_denied_page = access_denied()
    if not_elevated_page is None:
        not_elevated_page = not_elevated()

    @app.callback(
        [Output(container_id, "children"),
         Output(tabs_container_id, "style"),
         Output("auth-message-container", "children"),
         Output("auth-message-container", "style")],
        Input("token_data", "data")
    )
    def _auth_router(token_data):
        show = {"display": "block"}
        hide = {"display": "none"}
        auth_message_style = {"display": "block", "padding": "40px", "margin-top": "20px"}

        if not token_data:
            return main_content, hide, landing_page, auth_message_style
        if token_data.get("access_denied"):
            # Use custom message if provided in token_data, otherwise default
            custom_message = token_data.get("access_denied_message")
            base_url = token_data.get("webbase_data")
            page = access_denied_page if not custom_message else access_denied(custom_message, base_url)
            return main_content, hide, page, auth_message_style
        if require_elevated and not token_data.get("is_elevated", False):
            # Generate dynamic message with user info and correct B-Fabric link
            base_url = token_data.get("webbase_data")
            username = token_data.get("user_data", "Unknown")
            message = (
                f"Hello {username}, this application requires elevated permissions (web service access). "
                "This is expected behavior for regular users. "
                "Please contact an administrator if you need access to this application."
            )
            page = not_elevated_page if not base_url else not_elevated(message, base_url)
            return main_content, hide, page, auth_message_style
        return main_content, show, [], hide

    # Automatically register auth display callback
    register_auth_display_callback(app)

    return _auth_router


def register_auth_display_callback(app):
    """
    Register a callback to update the authentication display with the logged-in user.

    This callback updates the auth-display div in the header with the current user's
    login name when authenticated.

    Args:
        app: The Dash application instance.

    Example:
        >>> app = create_app(__name__)
        >>> app.layout = get_static_layout(...)
        >>> register_auth_display_callback(app)
    """
    @app.callback(
        Output("auth-display", "children"),
        [Input("token_data", "data"),
         Input("entity", "data")]
    )
    def update_auth_display(token_data, _entity_data):
        """Update authentication display with login name."""
        if not token_data:
            return html.Div()  # Empty div when not authenticated

        user_name = token_data.get("user_data", "Unknown User")
        return html.Div([
            html.I(className="fas fa-check-circle", style={"color": "green", "marginRight": "8px"}),
            html.Strong("Logged in as: "),
            html.Span(user_name),
        ])

    return update_auth_display