"""Tests for mcp.server.auth.provider module."""

from mcp.server.auth.provider import AccessToken, construct_redirect_uri, principal_components


def test_construct_redirect_uri_no_existing_params():
    """Test construct_redirect_uri with no existing query parameters."""
    base_uri = "http://localhost:8000/callback"
    result = construct_redirect_uri(base_uri, code="auth_code", state="test_state")

    assert "http://localhost:8000/callback?code=auth_code&state=test_state" == result


def test_construct_redirect_uri_with_existing_params():
    """Test construct_redirect_uri with existing query parameters (regression test for #1279)."""
    base_uri = "http://localhost:8000/callback?session_id=1234"
    result = construct_redirect_uri(base_uri, code="auth_code", state="test_state")

    # Should preserve existing params and add new ones
    assert "session_id=1234" in result
    assert "code=auth_code" in result
    assert "state=test_state" in result
    assert result.startswith("http://localhost:8000/callback?")


def test_construct_redirect_uri_multiple_existing_params():
    """Test construct_redirect_uri with multiple existing query parameters."""
    base_uri = "http://localhost:8000/callback?session_id=1234&user=test"
    result = construct_redirect_uri(base_uri, code="auth_code")

    assert "session_id=1234" in result
    assert "user=test" in result
    assert "code=auth_code" in result


def test_construct_redirect_uri_with_none_values():
    """Test construct_redirect_uri filters out None values."""
    base_uri = "http://localhost:8000/callback"
    result = construct_redirect_uri(base_uri, code="auth_code", state=None)

    assert result == "http://localhost:8000/callback?code=auth_code"
    assert "state" not in result


def test_construct_redirect_uri_empty_params():
    """Test construct_redirect_uri with no additional parameters."""
    base_uri = "http://localhost:8000/callback?existing=param"
    result = construct_redirect_uri(base_uri)

    assert result == "http://localhost:8000/callback?existing=param"


def test_construct_redirect_uri_duplicate_param_names():
    """Test construct_redirect_uri when adding param that already exists."""
    base_uri = "http://localhost:8000/callback?code=existing"
    result = construct_redirect_uri(base_uri, code="new_code")

    # Should contain both values (this is expected behavior of parse_qs/urlencode)
    assert "code=existing" in result
    assert "code=new_code" in result


def test_construct_redirect_uri_multivalued_existing_params():
    """Test construct_redirect_uri with existing multi-valued parameters."""
    base_uri = "http://localhost:8000/callback?scope=read&scope=write"
    result = construct_redirect_uri(base_uri, code="auth_code")

    assert "scope=read" in result
    assert "scope=write" in result
    assert "code=auth_code" in result


def test_construct_redirect_uri_encoded_values():
    """Test construct_redirect_uri handles URL encoding properly."""
    base_uri = "http://localhost:8000/callback"
    result = construct_redirect_uri(base_uri, state="test state with spaces")

    # urlencode uses + for spaces by default
    assert "state=test+state+with+spaces" in result


def test_principal_components_composes_client_issuer_subject():
    """The triple identifying a token's principal, degrading per missing component."""
    bare = AccessToken(token="t", client_id="client-1", scopes=[])
    assert principal_components(bare) == ("client-1", None, None)

    full = AccessToken(
        token="t", client_id="client-1", scopes=[], subject="alice", claims={"iss": "https://as.example"}
    )
    assert principal_components(full) == ("client-1", "https://as.example", "alice")
