from __future__ import annotations

from unittest.mock import patch

from amsdal_server.apps.common.events.auth import AuthenticateEvent
from amsdal_server.apps.common.events.server import MiddlewareSetupContext
from amsdal_server.apps.common.events.server import MiddlewareSetupEvent
from amsdal_server.apps.common.events.server import RouterSetupEvent
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.testclient import TestClient
from starlette.status import HTTP_401_UNAUTHORIZED

from amsdal_ml.app import MLPluginAppConfig
from amsdal_ml.mcp_server.mcp_oauth.event_listeners.auth_bridge_listener import OAuthAuthenticateBridgeListener
from amsdal_ml.mcp_server.mcp_oauth.event_listeners.server_setup import MCPMiddlewareSetupListener
from amsdal_ml.ml_config import ml_config

LISTENER_SETUP_CALLS = 2


def test_ml_plugin_app_config_subscribes_oauth_bridge_when_enabled(monkeypatch):
    monkeypatch.setattr(ml_config, 'oauth_enabled', True)

    with (
        patch('amsdal_ml.app.listen_to') as listen_to_mock,
        patch('amsdal_utils.events.EventBus.subscribe') as subscribe,
    ):
        listen_to_mock.side_effect = lambda _event: lambda _listener: _listener
        MLPluginAppConfig().on_setup()

    listen_to_mock.assert_any_call(RouterSetupEvent)
    listen_to_mock.assert_any_call(MiddlewareSetupEvent)
    assert listen_to_mock.call_count == LISTENER_SETUP_CALLS

    subscribe.assert_called_once_with(
        AuthenticateEvent,
        OAuthAuthenticateBridgeListener,
        before=['amsdal.contrib.auth.event_handlers.authenticate.AuthenticateUserListener'],
    )


def test_ml_plugin_app_config_skips_oauth_bridge_when_disabled(monkeypatch):
    monkeypatch.setattr(ml_config, 'oauth_enabled', False)

    with (
        patch('amsdal_ml.app.listen_to') as listen_to_mock,
        patch('amsdal_utils.events.EventBus.subscribe') as subscribe,
    ):
        listen_to_mock.side_effect = lambda _event: lambda _listener: _listener
        MLPluginAppConfig().on_setup()

    listen_to_mock.assert_any_call(RouterSetupEvent)
    listen_to_mock.assert_any_call(MiddlewareSetupEvent)
    assert listen_to_mock.call_count == LISTENER_SETUP_CALLS
    subscribe.assert_not_called()


def test_middleware_listener_installs_www_authenticate_when_oauth_enabled(monkeypatch):
    monkeypatch.setattr(ml_config, 'oauth_enabled', True)

    app = FastAPI()

    @app.get('/mcp/protected')
    def mcp_protected():
        return JSONResponse(status_code=401, content={'detail': 'unauthorized'})

    context = MiddlewareSetupContext(app=app)
    listener = MCPMiddlewareSetupListener()

    listener.handle(context, lambda ctx: ctx)

    response = TestClient(app).get('/mcp/protected')
    assert response.status_code == HTTP_401_UNAUTHORIZED
    assert response.headers.get('WWW-Authenticate') is not None


def test_middleware_listener_skips_www_authenticate_when_oauth_disabled(monkeypatch):
    monkeypatch.setattr(ml_config, 'oauth_enabled', False)

    app = FastAPI()

    @app.get('/mcp/protected')
    def mcp_protected():
        return JSONResponse(status_code=401, content={'detail': 'unauthorized'})

    context = MiddlewareSetupContext(app=app)
    listener = MCPMiddlewareSetupListener()

    listener.handle(context, lambda ctx: ctx)

    response = TestClient(app).get('/mcp/protected')
    assert response.status_code == HTTP_401_UNAUTHORIZED
    assert response.headers.get('WWW-Authenticate') is None
