"""Tests for GitHub App authentication."""

from __future__ import annotations

import httpx
import jwt as pyjwt
import respx
from helpers import WEBHOOK_SECRET

from github_app.auth import (
    generate_jwt,
    get_installation_token,
    verify_signature,
)


def test_generate_jwt_structure(mock_config):
    token = generate_jwt(mock_config)
    # Should be a 3-part JWT.
    parts = token.split(".")
    assert len(parts) == 3


def test_generate_jwt_claims(mock_config):
    token = generate_jwt(mock_config)
    claims = pyjwt.decode(
        token,
        options={"verify_signature": False},
        algorithms=["RS256"],
    )
    # PyJWT requires iss as string; Config.app_id is int, converted in generate_jwt.
    assert claims["iss"] == "12345"
    assert "iat" in claims
    assert "exp" in claims
    # 660 = 600s expiry + 60s backdate.
    assert claims["exp"] - claims["iat"] == 660


def test_verify_signature_valid():
    payload = b"test payload"
    import hashlib
    import hmac

    sig = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256,
    ).hexdigest()
    assert verify_signature(payload, f"sha256={sig}", WEBHOOK_SECRET)


def test_verify_signature_invalid():
    assert not verify_signature(b"payload", "sha256=wrong", WEBHOOK_SECRET)


def test_verify_signature_bad_prefix():
    assert not verify_signature(b"payload", "md5=abc", WEBHOOK_SECRET)


@respx.mock
async def test_get_installation_token_fetches(mock_config):
    respx.post(
        "https://api.github.com/app/installations/99/access_tokens",
    ).respond(json={"token": "ghs_test123"})

    async with httpx.AsyncClient() as client:
        token = await get_installation_token(
            mock_config,
            99,
            client=client,
        )

    assert token == "ghs_test123"


@respx.mock
async def test_get_installationtoken_caches(mock_config):
    route = respx.post(
        "https://api.github.com/app/installations/99/access_tokens",
    ).respond(json={"token": "ghs_cached"})

    async with httpx.AsyncClient() as client:
        t1 = await get_installation_token(mock_config, 99, client=client)
        t2 = await get_installation_token(mock_config, 99, client=client)

    assert t1 == t2 == "ghs_cached"
    assert route.call_count == 1
