from __future__ import annotations

import asyncio

import jwt
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient

from amsdal_ml.mcp_server.mcp_oauth import oauth_router
from amsdal_ml.mcp_server.mcp_oauth.routes.register import register
from amsdal_ml.mcp_server.mcp_oauth.services.models import RegisterRequest
from amsdal_ml.mcp_server.mcp_oauth.services.types import JWT_ALGORITHM
from amsdal_ml.mcp_server.mcp_oauth.services.types import ClientIdTokenClaims
from amsdal_ml.mcp_server.mcp_oauth.services.types import OAuthConstants
from amsdal_ml.ml_config import ml_config

HTTP_NOT_FOUND = 404


def call_register(req: RegisterRequest):
    return asyncio.run(register(req))


def test_register_raises_when_oauth_disabled(monkeypatch):
    monkeypatch.setattr(ml_config, 'oauth_enabled', False)
    app = FastAPI()
    app.include_router(oauth_router)
    response = TestClient(app).post(
        '/register',
        json={
            'client_name': 'test-client',
            'redirect_uris': ['https://chatgpt.com/connector_platform_oauth_redirect'],
            'grant_types': ['authorization_code'],
            'response_types': ['code'],
        },
    )

    assert response.status_code == HTTP_NOT_FOUND
    assert response.json()['detail'] == 'OAuth disabled'


def test_register_returns_signed_client_id(oauth_signing_key):
    req = RegisterRequest(
        client_name='test-client',
        redirect_uris=['https://chatgpt.com/connector_platform_oauth_redirect'],
        grant_types=['authorization_code'],
        response_types=['code'],
    )

    response = call_register(req)

    payload = jwt.decode(
        response.client_id,
        oauth_signing_key,
        algorithms=[JWT_ALGORITHM],
    )

    assert payload[ClientIdTokenClaims.REDIRECT_URIS.value] == req.redirect_uris
    assert payload[ClientIdTokenClaims.GRANT_TYPES.value] == req.grant_types
    assert payload[ClientIdTokenClaims.RESPONSE_TYPES.value] == req.response_types
    assert payload[ClientIdTokenClaims.TOKEN_ENDPOINT_AUTH_METHOD.value] == (
        OAuthConstants.TOKEN_ENDPOINT_AUTH_NONE.value
    )
    assert payload[ClientIdTokenClaims.ISSUER.value] == ml_config.oauth_issuer
    assert isinstance(payload[ClientIdTokenClaims.ISSUED_AT.value], int)
    assert isinstance(payload[ClientIdTokenClaims.EXPIRATION.value], int)
    assert isinstance(payload[ClientIdTokenClaims.JWT_ID.value], str)
    assert response.expires_at == payload[ClientIdTokenClaims.EXPIRATION.value]


def test_register_raises_when_signing_key_missing(monkeypatch):
    from amsdal.contrib.auth.errors import AuthenticationError
    from amsdal.contrib.auth.settings import auth_settings

    monkeypatch.setattr(auth_settings, 'AUTH_JWT_KEY', '', raising=False)

    with pytest.raises(AuthenticationError, match='JWT key is not set'):
        call_register(
            RegisterRequest(
                client_name='test-client',
                redirect_uris=['https://chatgpt.com/connector_platform_oauth_redirect'],
                grant_types=['authorization_code'],
                response_types=['code'],
            )
        )
