"""Shared test fixtures: RSA keys, test JWTs, mock JWKS endpoint."""

import json
import time
import uuid

import jwt as pyjwt
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

from conduit_auth import AuthSettings
from conduit_auth.token import get_key_cache


@pytest.fixture(autouse=True)
def _clear_key_cache():
    """Clear the JWKS key cache between tests."""
    get_key_cache().clear()


@pytest.fixture
def rsa_keypair():
    """Generate a test RSA key pair."""
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
    )
    return private_key


@pytest.fixture
def kid():
    """A fixed key ID for test tokens."""
    return "test-kid-12345"


@pytest.fixture
def jwks_keys(rsa_keypair, kid):
    """JWKS key list matching the test RSA key."""
    public_key = rsa_keypair.public_key()
    public_numbers = public_key.public_numbers()

    # Encode as base64url (matching JWKS format)
    import base64

    def _b64url(num: int, length: int) -> str:
        return (
            base64.urlsafe_b64encode(num.to_bytes(length, "big"))
            .rstrip(b"=")
            .decode()
        )

    n_bytes = (public_numbers.n.bit_length() + 7) // 8

    return [
        {
            "kty": "RSA",
            "use": "sig",
            "kid": kid,
            "n": _b64url(public_numbers.n, n_bytes),
            "e": _b64url(public_numbers.e, 3),
            "alg": "RS256",
        }
    ]


@pytest.fixture
def test_tenant_id():
    return "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"


@pytest.fixture
def test_user_id():
    return "11111111-2222-3333-4444-555555555555"


@pytest.fixture
def test_client_id():
    return "cccccccc-dddd-eeee-ffff-000000000000"


@pytest.fixture
def auth_settings(test_client_id):
    """AuthSettings for testing."""
    return AuthSettings(
        ENTRA_CLIENT_ID=test_client_id,
        AUTH_DISABLED=False,
    )


@pytest.fixture
def make_token(rsa_keypair, kid, test_tenant_id, test_user_id, test_client_id):
    """Factory for creating signed test JWTs."""

    def _make(
        tenant_id: str | None = None,
        user_id: str | None = None,
        email: str = "user@example.com",
        name: str = "Test User",
        audience: str | None = None,
        issuer: str | None = None,
        expired: bool = False,
        extra_claims: dict | None = None,
        use_kid: str | None = None,
    ) -> str:
        tid = tenant_id or test_tenant_id
        now = time.time()

        claims = {
            "aud": audience or test_client_id,
            "iss": issuer
            or f"https://login.microsoftonline.com/{tid}/v2.0",
            "iat": int(now) - 60,
            "nbf": int(now) - 60,
            "exp": int(now) - 300 if expired else int(now) + 3600,
            "tid": tid,
            "oid": user_id or test_user_id,
            "preferred_username": email,
            "name": name,
            "sub": str(uuid.uuid4()),
        }
        if extra_claims:
            claims.update(extra_claims)

        private_pem = rsa_keypair.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption(),
        )

        return pyjwt.encode(
            claims,
            private_pem,
            algorithm="RS256",
            headers={"kid": use_kid or kid},
        )

    return _make
