import base64
import hashlib
import json

import pytest

from goodnews import oauth_google as g


def _seg(d: dict) -> str:
    return base64.urlsafe_b64encode(json.dumps(d).encode()).rstrip(b"=").decode()


def _token(claims: dict) -> str:
    return f"{_seg({'alg': 'RS256'})}.{_seg(claims)}.sig"


def test_pkce_challenge_matches_verifier():
    verifier, challenge = g.new_pkce()
    expected = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode()).digest()).rstrip(b"=").decode()
    assert challenge == expected


def test_auth_url_has_required_params(monkeypatch):
    monkeypatch.setenv("GOODNEWS_GOOGLE_CLIENT_ID", "cid")
    url = g.auth_url("https://x/cb", "state123", "chal")
    for needle in ["client_id=cid", "redirect_uri=https", "state=state123",
                   "code_challenge=chal", "code_challenge_method=S256", "scope=openid"]:
        assert needle in url


def test_verify_id_token_happy(monkeypatch):
    monkeypatch.setenv("GOODNEWS_GOOGLE_CLIENT_ID", "cid")
    tok = _token({"iss": "https://accounts.google.com", "aud": "cid", "exp": 9999999999,
                  "sub": "g-123", "email": "a@b.com", "email_verified": True, "name": "A",
                  "picture": "https://x/p.jpg"})
    info = g.verify_id_token(tok)
    assert info == {"sub": "g-123", "email": "a@b.com", "name": "A", "picture": "https://x/p.jpg"}


def test_verify_id_token_rejects(monkeypatch):
    monkeypatch.setenv("GOODNEWS_GOOGLE_CLIENT_ID", "cid")
    base = {"iss": "https://accounts.google.com", "aud": "cid", "exp": 9999999999,
            "sub": "g", "email": "a@b.com", "email_verified": True}
    with pytest.raises(ValueError):  # wrong audience
        g.verify_id_token(_token({**base, "aud": "other"}))
    with pytest.raises(ValueError):  # bad issuer
        g.verify_id_token(_token({**base, "iss": "evil.com"}))
    with pytest.raises(ValueError):  # expired
        g.verify_id_token(_token({**base, "exp": 1}))
    with pytest.raises(ValueError):  # email not verified
        g.verify_id_token(_token({**base, "email_verified": False}))
